diff --git a/.vscode/settings.json b/.vscode/settings.json index b5da1e8e6..05d23f3bb 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -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" } } diff --git a/CHANGELOG.md b/CHANGELOG.md index cf7d8465a..a3e1ef4a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,16 +5,44 @@ 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 - ### Changed -- +- ### Fixed -- (Clientes -> Listado extendido) Resuelto error al filtrar por clientes inactivos desde la columna "Activo" +- + +## [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 ## [2308.01] - 2023-03-09 diff --git a/Dockerfile b/Dockerfile index a59725f77..ee87cd0d0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -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 diff --git a/back/methods/account/change-password.js b/back/methods/account/change-password.js index c0956b193..b8f9de341 100644 --- a/back/methods/account/change-password.js +++ b/back/methods/account/change-password.js @@ -2,6 +2,7 @@ module.exports = Self => { Self.remoteMethod('changePassword', { description: 'Changes the user password', + accessType: 'WRITE', accepts: [ { arg: 'id', diff --git a/back/methods/account/set-password.js b/back/methods/account/set-password.js index ab4d3b3fe..093935948 100644 --- a/back/methods/account/set-password.js +++ b/back/methods/account/set-password.js @@ -1,6 +1,7 @@ module.exports = Self => { Self.remoteMethod('setPassword', { description: 'Sets the user password', + accessType: 'WRITE', accepts: [ { arg: 'id', diff --git a/back/methods/chat/send.js b/back/methods/chat/send.js index 915120d49..79b20e307 100644 --- a/back/methods/chat/send.js +++ b/back/methods/chat/send.js @@ -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; } diff --git a/back/methods/chat/sendCheckingPresence.js b/back/methods/chat/sendCheckingPresence.js index 883a1b693..29232490a 100644 --- a/back/methods/chat/sendCheckingPresence.js +++ b/back/methods/chat/sendCheckingPresence.js @@ -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; }; }; diff --git a/back/methods/chat/sendQueued.js b/back/methods/chat/sendQueued.js index 66fbfcdc5..ef1a417ab 100644 --- a/back/methods/chat/sendQueued.js +++ b/back/methods/chat/sendQueued.js @@ -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 diff --git a/back/methods/chat/spec/sendQueued.spec.js b/back/methods/chat/spec/sendQueued.spec.js index ed791756b..67cd47f4a 100644 --- a/back/methods/chat/spec/sendQueued.spec.js +++ b/back/methods/chat/spec/sendQueued.spec.js @@ -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 }; diff --git a/back/methods/collection/previousLabel.js b/back/methods/collection/previousLabel.js index fb2df8133..e3dac1ab4 100644 --- a/back/methods/collection/previousLabel.js +++ b/back/methods/collection/previousLabel.js @@ -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'); }; diff --git a/back/methods/collection/spec/setSaleQuantity.spec.js b/back/methods/collection/spec/setSaleQuantity.spec.js index 63dc3bd2d..acdf2ebb5 100644 --- a/back/methods/collection/spec/setSaleQuantity.spec.js +++ b/back/methods/collection/spec/setSaleQuantity.spec.js @@ -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({}); diff --git a/back/methods/dms/saveSign.js b/back/methods/dms/saveSign.js deleted file mode 100644 index ed462a301..000000000 --- a/back/methods/dms/saveSign.js +++ /dev/null @@ -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; - } - }; -}; diff --git a/back/methods/image/upload.js b/back/methods/image/upload.js index 143da275e..1de0064f6 100644 --- a/back/methods/image/upload.js +++ b/back/methods/image/upload.js @@ -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) { } } }; }; diff --git a/back/methods/osticket/closeTicket.js b/back/methods/osticket/closeTicket.js index 32b369c8d..aa827bbbb 100644 --- a/back/methods/osticket/closeTicket.js +++ b/back/methods/osticket/closeTicket.js @@ -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); diff --git a/back/models/delivery.json b/back/models/delivery.json index 65a0eef1b..c66c31b45 100644 --- a/back/models/delivery.json +++ b/back/models/delivery.json @@ -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" + } + } } diff --git a/back/models/dms.js b/back/models/dms.js index fc586201f..24c072f56 100644 --- a/back/models/dms.js +++ b/back/models/dms.js @@ -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; diff --git a/back/models/image.js b/back/models/image.js index 3d3b03879..61c6199b8 100644 --- a/back/models/image.js +++ b/back/models/image.js @@ -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(); + }); + }); } }; }; diff --git a/back/models/user.json b/back/models/user.json index 921362e0e..d992fd9db 100644 --- a/back/models/user.json +++ b/back/models/user.json @@ -4,7 +4,8 @@ "options": { "mysql": { "table": "salix.User" - } + }, + "resetPasswordTokenTTL": "604800" }, "properties": { "id": { diff --git a/db/changes/230801/00-ticketConfig.sql b/db/changes/230801/00-ticketConfig.sql new file mode 100644 index 000000000..ca63dbf63 --- /dev/null +++ b/db/changes/230801/00-ticketConfig.sql @@ -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'; diff --git a/db/changes/231001/00-delivery.sql b/db/changes/231001/00-delivery.sql new file mode 100644 index 000000000..3a9269183 --- /dev/null +++ b/db/changes/231001/00-delivery.sql @@ -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 ; diff --git a/db/changes/231001/00-insertI18n.sql b/db/changes/231001/00-insertI18n.sql deleted file mode 100644 index 2baa6c9ab..000000000 --- a/db/changes/231001/00-insertI18n.sql +++ /dev/null @@ -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.'); diff --git a/db/changes/231001/00-invoiceOut.sql b/db/changes/231001/00-invoiceOut.sql new file mode 100644 index 000000000..4404c8f4a --- /dev/null +++ b/db/changes/231001/00-invoiceOut.sql @@ -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'); \ No newline at end of file diff --git a/db/changes/230402/00-invoiceOut_getWeight.sql b/db/changes/231001/00-invoiceOut_getWeight.sql similarity index 83% rename from db/changes/230402/00-invoiceOut_getWeight.sql rename to db/changes/231001/00-invoiceOut_getWeight.sql index 4ca284857..3f34b6fb7 100644 --- a/db/changes/230402/00-invoiceOut_getWeight.sql +++ b/db/changes/231001/00-invoiceOut_getWeight.sql @@ -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; diff --git a/db/changes/231001/00-report.sql b/db/changes/231001/00-report.sql new file mode 100644 index 000000000..0bc7c8da4 --- /dev/null +++ b/db/changes/231001/00-report.sql @@ -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; + diff --git a/db/changes/231001/01-invoiceOut_getMaxIssued.sql b/db/changes/231001/01-invoiceOut_getMaxIssued.sql new file mode 100644 index 000000000..e120b949d --- /dev/null +++ b/db/changes/231001/01-invoiceOut_getMaxIssued.sql @@ -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 ; \ No newline at end of file diff --git a/db/changes/231001/02-invoiceOut_new.sql b/db/changes/231001/02-invoiceOut_new.sql new file mode 100644 index 000000000..0fd91ef58 --- /dev/null +++ b/db/changes/231001/02-invoiceOut_new.sql @@ -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 ; \ No newline at end of file diff --git a/db/changes/231001/03-ticketPackaging_add.sql b/db/changes/231001/03-ticketPackaging_add.sql new file mode 100644 index 000000000..a7cf1d1d3 --- /dev/null +++ b/db/changes/231001/03-ticketPackaging_add.sql @@ -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 ; \ No newline at end of file diff --git a/db/changes/231201/00-ACL.sql b/db/changes/231201/00-ACL.sql new file mode 100644 index 000000000..47a818977 --- /dev/null +++ b/db/changes/231201/00-ACL.sql @@ -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'); diff --git a/db/changes/231201/00-chatRefactor.sql b/db/changes/231201/00-chatRefactor.sql new file mode 100644 index 000000000..66d1bf3bf --- /dev/null +++ b/db/changes/231201/00-chatRefactor.sql @@ -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; diff --git a/db/changes/231201/00-invoiceInSerial.sql b/db/changes/231201/00-invoiceInSerial.sql new file mode 100644 index 000000000..de476027c --- /dev/null +++ b/db/changes/231201/00-invoiceInSerial.sql @@ -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'); diff --git a/db/changes/231201/00-itemType_isFragile.sql b/db/changes/231201/00-itemType_isFragile.sql new file mode 100644 index 000000000..ecc1bfbb2 --- /dev/null +++ b/db/changes/231201/00-itemType_isFragile.sql @@ -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'); + diff --git a/db/changes/231201/00-mailACL.sql b/db/changes/231201/00-mailACL.sql new file mode 100644 index 000000000..ac687818d --- /dev/null +++ b/db/changes/231201/00-mailACL.sql @@ -0,0 +1,2 @@ +INSERT INTO `salix`.`ACL` ( model, property, accessType, permission, principalType, principalId) +VALUES('Mail', '*', '*', 'ALLOW', 'ROLE', 'employee'); diff --git a/db/changes/231201/00-operator.sql b/db/changes/231201/00-operator.sql new file mode 100644 index 000000000..9b7815b41 --- /dev/null +++ b/db/changes/231201/00-operator.sql @@ -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' + ) \ No newline at end of file diff --git a/db/changes/231201/00-supplierAccount_deleteTriggers.sql b/db/changes/231201/00-supplierAccount_deleteTriggers.sql new file mode 100644 index 000000000..d7f9f734a --- /dev/null +++ b/db/changes/231201/00-supplierAccount_deleteTriggers.sql @@ -0,0 +1,3 @@ +DROP TRIGGER `vn`.`supplierAccount_afterInsert`; +DROP TRIGGER `vn`.`supplierAccount_afterUpdate`; +DROP TRIGGER `vn`.`supplierAccount_afterDelete`; diff --git a/db/changes/231201/00-ticket_getWarnings.sql b/db/changes/231201/00-ticket_getWarnings.sql new file mode 100644 index 000000000..5253b58ab --- /dev/null +++ b/db/changes/231201/00-ticket_getWarnings.sql @@ -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 ; diff --git a/db/changes/231201/00-wagon.sql b/db/changes/231201/00-wagon.sql new file mode 100644 index 000000000..3e4d225d7 --- /dev/null +++ b/db/changes/231201/00-wagon.sql @@ -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'); diff --git a/db/changes/231202/00-delivery.sql b/db/changes/231202/00-delivery.sql new file mode 100644 index 000000000..3a9269183 --- /dev/null +++ b/db/changes/231202/00-delivery.sql @@ -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 ; diff --git a/db/changes/231203/00-delivery.sql b/db/changes/231203/00-delivery.sql new file mode 100644 index 000000000..0815ec421 --- /dev/null +++ b/db/changes/231203/00-delivery.sql @@ -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 ; diff --git a/db/changes/231204/00-rollbackDelivery.sql b/db/changes/231204/00-rollbackDelivery.sql new file mode 100644 index 000000000..d7fa6b587 --- /dev/null +++ b/db/changes/231204/00-rollbackDelivery.sql @@ -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 ; diff --git a/db/changes/231401/00-claimBeginningAfterInsert.sql b/db/changes/231401/00-claimBeginningAfterInsert.sql new file mode 100644 index 000000000..230b6defb --- /dev/null +++ b/db/changes/231401/00-claimBeginningAfterInsert.sql @@ -0,0 +1 @@ +DROP TRIGGER IF EXISTS `vn`.`claimBeginning_afterInsert`; diff --git a/db/changes/231401/00-clientBeforeUpdate.sql b/db/changes/231401/00-clientBeforeUpdate.sql new file mode 100644 index 000000000..8f9f70dd5 --- /dev/null +++ b/db/changes/231401/00-clientBeforeUpdate.sql @@ -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 ; diff --git a/db/changes/231401/00-hotfixDelivery.sql b/db/changes/231401/00-hotfixDelivery.sql new file mode 100644 index 000000000..4628cc1db --- /dev/null +++ b/db/changes/231401/00-hotfixDelivery.sql @@ -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 ; diff --git a/db/changes/231401/00-invoiceOutAfterInsert.sql b/db/changes/231401/00-invoiceOutAfterInsert.sql new file mode 100644 index 000000000..adeaf9834 --- /dev/null +++ b/db/changes/231401/00-invoiceOutAfterInsert.sql @@ -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 ; + diff --git a/db/changes/231401/00-negativeBases.sql b/db/changes/231401/00-negativeBases.sql new file mode 100644 index 000000000..0bdc6f2dc --- /dev/null +++ b/db/changes/231401/00-negativeBases.sql @@ -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'); diff --git a/db/changes/231401/00-workerNotes.sql b/db/changes/231401/00-workerNotes.sql new file mode 100644 index 000000000..0d9eaae7e --- /dev/null +++ b/db/changes/231401/00-workerNotes.sql @@ -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'); diff --git a/db/changes/231001/.gitkeep b/db/changes/231601/.gitkeep similarity index 100% rename from db/changes/231001/.gitkeep rename to db/changes/231601/.gitkeep diff --git a/db/changes/231601/00-insertI18n.sql b/db/changes/231601/00-insertI18n.sql new file mode 100644 index 000000000..f86cb6a73 --- /dev/null +++ b/db/changes/231601/00-insertI18n.sql @@ -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.'); diff --git a/db/changes/231001/00-newCompanyI18n.sql b/db/changes/231601/00-newCompanyI18n.sql similarity index 100% rename from db/changes/231001/00-newCompanyI18n.sql rename to db/changes/231601/00-newCompanyI18n.sql diff --git a/db/changes/231001/00-newTableWeb.sql b/db/changes/231601/00-newTableWeb.sql similarity index 100% rename from db/changes/231001/00-newTableWeb.sql rename to db/changes/231601/00-newTableWeb.sql diff --git a/db/changes/231601/00-observationEmailACL.sql b/db/changes/231601/00-observationEmailACL.sql new file mode 100644 index 000000000..1a5d475e8 --- /dev/null +++ b/db/changes/231601/00-observationEmailACL.sql @@ -0,0 +1,3 @@ +INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) + VALUES + ('Defaulter', 'observationEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'); diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 2f1c7a806..b352b83d0 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -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); + + + diff --git a/db/dump/structure.sql b/db/dump/structure.sql index 929d1cc64..90e4c4bc9 100644 --- a/db/dump/structure.sql +++ b/db/dump/structure.sql @@ -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 + diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index 9840696c2..84db638e3 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -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}}"]', diff --git a/e2e/paths/01-salix/03_smartTable_searchBar_integrations.spec.js b/e2e/paths/01-salix/03_smartTable_searchBar_integrations.spec.js index ad558ace2..a3d747f1c 100644 --- a/e2e/paths/01-salix/03_smartTable_searchBar_integrations.spec.js +++ b/e2e/paths/01-salix/03_smartTable_searchBar_integrations.spec.js @@ -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'); }); }); }); diff --git a/e2e/paths/02-client/13_log.spec.js b/e2e/paths/02-client/13_log.spec.js index 8f186d842..5292b1a65 100644 --- a/e2e/paths/02-client/13_log.spec.js +++ b/e2e/paths/02-client/13_log.spec.js @@ -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'); - }); }); diff --git a/e2e/paths/02-client/21_defaulter.spec.js b/e2e/paths/02-client/21_defaulter.spec.js index 0eb16441f..97e62abef 100644 --- a/e2e/paths/02-client/21_defaulter.spec.js +++ b/e2e/paths/02-client/21_defaulter.spec.js @@ -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'); diff --git a/e2e/paths/03-worker/04_time_control.spec.js b/e2e/paths/03-worker/04_time_control.spec.js index eb1417ba9..5f64aa6ce 100644 --- a/e2e/paths/03-worker/04_time_control.spec.js +++ b/e2e/paths/03-worker/04_time_control.spec.js @@ -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'); diff --git a/e2e/paths/03-worker/06_create.spec.js b/e2e/paths/03-worker/06_create.spec.js index 5f6f5cf9f..98e67edbf 100644 --- a/e2e/paths/03-worker/06_create.spec.js +++ b/e2e/paths/03-worker/06_create.spec.js @@ -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 diff --git a/e2e/paths/03-worker/08_add_notes.spec.js b/e2e/paths/03-worker/08_add_notes.spec.js new file mode 100644 index 000000000..bdc475c90 --- /dev/null +++ b/e2e/paths/03-worker/08_add_notes.spec.js @@ -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'); + }); +}); diff --git a/e2e/paths/04-item/10_item_log.spec.js b/e2e/paths/04-item/10_item_log.spec.js index 2a885fe6f..dc467044d 100644 --- a/e2e/paths/04-item/10_item_log.spec.js +++ b/e2e/paths/04-item/10_item_log.spec.js @@ -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'); - }); }); diff --git a/e2e/paths/04-item/13_fixedPrice.spec.js b/e2e/paths/04-item/13_fixedPrice.spec.js index 1b0f82d83..ec8238b87 100644 --- a/e2e/paths/04-item/13_fixedPrice.spec.js +++ b/e2e/paths/04-item/13_fixedPrice.spec.js @@ -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'); diff --git a/e2e/paths/05-ticket/01-sale/02_edit_sale.spec.js b/e2e/paths/05-ticket/01-sale/02_edit_sale.spec.js index 36161ae1d..323646d29 100644 --- a/e2e/paths/05-ticket/01-sale/02_edit_sale.spec.js +++ b/e2e/paths/05-ticket/01-sale/02_edit_sale.spec.js @@ -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'); }); diff --git a/e2e/paths/05-ticket/01_observations.spec.js b/e2e/paths/05-ticket/01_observations.spec.js index 45b4ebb3e..cf37f9ff1 100644 --- a/e2e/paths/05-ticket/01_observations.spec.js +++ b/e2e/paths/05-ticket/01_observations.spec.js @@ -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'); }); diff --git a/e2e/paths/05-ticket/02_expeditions_and_log.spec.js b/e2e/paths/05-ticket/02_expeditions_and_log.spec.js index ae5e2fb0c..edccd5561 100644 --- a/e2e/paths/05-ticket/02_expeditions_and_log.spec.js +++ b/e2e/paths/05-ticket/02_expeditions_and_log.spec.js @@ -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'); - }); }); diff --git a/e2e/paths/05-ticket/17_log.spec.js b/e2e/paths/05-ticket/17_log.spec.js index 32829ee74..e1da2df44 100644 --- a/e2e/paths/05-ticket/17_log.spec.js +++ b/e2e/paths/05-ticket/17_log.spec.js @@ -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'); - }); }); diff --git a/e2e/paths/05-ticket/21_future.spec.js b/e2e/paths/05-ticket/21_future.spec.js index 2b8057247..626056958 100644 --- a/e2e/paths/05-ticket/21_future.spec.js +++ b/e2e/paths/05-ticket/21_future.spec.js @@ -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); diff --git a/e2e/paths/05-ticket/22_advance.spec.js b/e2e/paths/05-ticket/22_advance.spec.js index f8442bf12..15f9dd5bb 100644 --- a/e2e/paths/05-ticket/22_advance.spec.js +++ b/e2e/paths/05-ticket/22_advance.spec.js @@ -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'); diff --git a/e2e/paths/09-invoice-in/05_negative_bases.spec.js b/e2e/paths/09-invoice-in/05_negative_bases.spec.js new file mode 100644 index 000000000..4c9fe651f --- /dev/null +++ b/e2e/paths/09-invoice-in/05_negative_bases.spec.js @@ -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(); + }); +}); diff --git a/e2e/paths/09-invoice-in/05_serial.spec.js b/e2e/paths/09-invoice-in/05_serial.spec.js new file mode 100644 index 000000000..3aa94f48c --- /dev/null +++ b/e2e/paths/09-invoice-in/05_serial.spec.js @@ -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'); + }); +}); diff --git a/e2e/paths/09-invoice-out/03_manualInvoice.spec.js b/e2e/paths/09-invoice-out/03_manualInvoice.spec.js index fa7cbed29..abb9ca7e7 100644 --- a/e2e/paths/09-invoice-out/03_manualInvoice.spec.js +++ b/e2e/paths/09-invoice-out/03_manualInvoice.spec.js @@ -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); }); diff --git a/e2e/paths/09-invoice-out/04_globalInvoice.spec.js b/e2e/paths/09-invoice-out/04_globalInvoice.spec.js index 74efafd2d..23aa3593c 100644 --- a/e2e/paths/09-invoice-out/04_globalInvoice.spec.js +++ b/e2e/paths/09-invoice-out/04_globalInvoice.spec.js @@ -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); }); }); diff --git a/e2e/paths/10-travel/02_basic_data_and_log.spec.js b/e2e/paths/10-travel/02_basic_data_and_log.spec.js index 341b38f59..5abf8a65e 100644 --- a/e2e/paths/10-travel/02_basic_data_and_log.spec.js +++ b/e2e/paths/10-travel/02_basic_data_and_log.spec.js @@ -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!'); diff --git a/e2e/paths/10-travel/03_descriptor.spec.js b/e2e/paths/10-travel/03_descriptor.spec.js index 79dcad514..3752400c6 100644 --- a/e2e/paths/10-travel/03_descriptor.spec.js +++ b/e2e/paths/10-travel/03_descriptor.spec.js @@ -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(); diff --git a/e2e/paths/10-travel/05_thermograph.spec.js b/e2e/paths/10-travel/05_thermograph.spec.js index a99dc8352..c9709f2f5 100644 --- a/e2e/paths/10-travel/05_thermograph.spec.js +++ b/e2e/paths/10-travel/05_thermograph.spec.js @@ -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'); }); diff --git a/e2e/paths/10-travel/06_search_panel.spec.js b/e2e/paths/10-travel/06_search_panel.spec.js new file mode 100644 index 000000000..420ceaf48 --- /dev/null +++ b/e2e/paths/10-travel/06_search_panel.spec.js @@ -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'); + }); +}); diff --git a/e2e/paths/11-zone/02_descriptor.spec.js b/e2e/paths/11-zone/02_descriptor.spec.js index 1de84d601..f3c0e7740 100644 --- a/e2e/paths/11-zone/02_descriptor.spec.js +++ b/e2e/paths/11-zone/02_descriptor.spec.js @@ -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'); - }); }); diff --git a/e2e/paths/13-supplier/02_basic_data.spec.js b/e2e/paths/13-supplier/02_basic_data.spec.js index 9d86e11d4..72ea6d890 100644 --- a/e2e/paths/13-supplier/02_basic_data.spec.js +++ b/e2e/paths/13-supplier/02_basic_data.spec.js @@ -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'); - }); }); diff --git a/front/core/components/calendar/index.html b/front/core/components/calendar/index.html index 086fe4338..4d02f9ec0 100644 --- a/front/core/components/calendar/index.html +++ b/front/core/components/calendar/index.html @@ -24,7 +24,7 @@
{{::day.localeChar}}
@@ -57,4 +57,4 @@
- \ No newline at end of file + diff --git a/front/core/components/calendar/index.js b/front/core/components/calendar/index.js index 17ccbf041..f30dac14f 100644 --- a/front/core/components/calendar/index.js +++ b/front/core/components/calendar/index.js @@ -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: '=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" } } } diff --git a/front/salix/components/layout/style.scss b/front/salix/components/layout/style.scss index 612366228..6697bb1b0 100644 --- a/front/salix/components/layout/style.scss +++ b/front/salix/components/layout/style.scss @@ -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 { diff --git a/front/salix/components/upload-photo/index.js b/front/salix/components/upload-photo/index.js index da1fda923..c9774d037 100644 --- a/front/salix/components/upload-photo/index.js +++ b/front/salix/components/upload-photo/index.js @@ -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) diff --git a/loopback/common/methods/vn-model/printService.js b/loopback/common/methods/vn-model/printService.js new file mode 100644 index 000000000..5cd571d4c --- /dev/null +++ b/loopback/common/methods/vn-model/printService.js @@ -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(); + }; +}; diff --git a/loopback/common/methods/vn-model/specs/crud.spec.js b/loopback/common/methods/vn-model/specs/crud.spec.js index 4aa35c14d..56af72bd9 100644 --- a/loopback/common/methods/vn-model/specs/crud.spec.js +++ b/loopback/common/methods/vn-model/specs/crud.spec.js @@ -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; diff --git a/loopback/common/methods/vn-model/specs/rewriteDbError.spec.js b/loopback/common/methods/vn-model/specs/rewriteDbError.spec.js index 1c4d53266..a3dba14d7 100644 --- a/loopback/common/methods/vn-model/specs/rewriteDbError.spec.js +++ b/loopback/common/methods/vn-model/specs/rewriteDbError.spec.js @@ -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; diff --git a/loopback/common/models/loggable.js b/loopback/common/models/loggable.js index 28a6075d0..360c84566 100644 --- a/loopback/common/models/loggable.js +++ b/loopback/common/models/loggable.js @@ -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'; - } }; diff --git a/loopback/common/models/vn-model.js b/loopback/common/models/vn-model.js index cc3eede8e..cebd37eac 100644 --- a/loopback/common/models/vn-model.js +++ b/loopback/common/models/vn-model.js @@ -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() { diff --git a/loopback/locale/en.json b/loopback/locale/en.json index dbe25dea3..e9fd67209 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -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" -} \ No newline at end of file +} diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 507cc9003..33741d395 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -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" } diff --git a/loopback/server/connectors/vn-mysql.js b/loopback/server/connectors/vn-mysql.js index fde0ddcf6..b08f69cb1 100644 --- a/loopback/server/connectors/vn-mysql.js +++ b/loopback/server/connectors/vn-mysql.js @@ -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, []); + } + }); +}; diff --git a/loopback/util/log.js b/loopback/util/log.js index e26022c35..76e87781d 100644 --- a/loopback/util/log.js +++ b/loopback/util/log.js @@ -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) diff --git a/modules/claim/back/methods/claim-state/isEditable.js b/modules/claim/back/methods/claim-state/isEditable.js index 2d0a8dc44..ad51d543a 100644 --- a/modules/claim/back/methods/claim-state/isEditable.js +++ b/modules/claim/back/methods/claim-state/isEditable.js @@ -26,13 +26,13 @@ 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); }; }; diff --git a/modules/claim/back/methods/claim/claimPickupPdf.js b/modules/claim/back/methods/claim/claimPickupPdf.js index 0e3abe908..4927efa0f 100644 --- a/modules/claim/back/methods/claim/claimPickupPdf.js +++ b/modules/claim/back/methods/claim/claimPickupPdf.js @@ -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'); }; diff --git a/modules/claim/back/methods/claim/logs.js b/modules/claim/back/methods/claim/logs.js index c7e69680b..f47513e9e 100644 --- a/modules/claim/back/methods/claim/logs.js +++ b/modules/claim/back/methods/claim/logs.js @@ -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) { diff --git a/modules/claim/back/methods/claim/specs/createFromSales.spec.js b/modules/claim/back/methods/claim/specs/createFromSales.spec.js index 7cf663caf..fe009c1c3 100644 --- a/modules/claim/back/methods/claim/specs/createFromSales.spec.js +++ b/modules/claim/back/methods/claim/specs/createFromSales.spec.js @@ -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 }]; diff --git a/modules/claim/back/methods/claim/specs/regularizeClaim.spec.js b/modules/claim/back/methods/claim/specs/regularizeClaim.spec.js index bf26d2255..276843c32 100644 --- a/modules/claim/back/methods/claim/specs/regularizeClaim.spec.js +++ b/modules/claim/back/methods/claim/specs/regularizeClaim.spec.js @@ -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({}); diff --git a/modules/claim/back/methods/claim/specs/updateClaim.spec.js b/modules/claim/back/methods/claim/specs/updateClaim.spec.js index 113df35c9..d367fb89f 100644 --- a/modules/claim/back/methods/claim/specs/updateClaim.spec.js +++ b/modules/claim/back/methods/claim/specs/updateClaim.spec.js @@ -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, diff --git a/modules/claim/back/methods/claim/specs/updateClaimAction.spec.js b/modules/claim/back/methods/claim/specs/updateClaimAction.spec.js index 12ab45fac..2f16d002c 100644 --- a/modules/claim/back/methods/claim/specs/updateClaimAction.spec.js +++ b/modules/claim/back/methods/claim/specs/updateClaimAction.spec.js @@ -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, diff --git a/modules/claim/back/models/claim-beginning.js b/modules/claim/back/models/claim-beginning.js index 4c4b59737..4b870e5ea 100644 --- a/modules/claim/back/models/claim-beginning.js +++ b/modules/claim/back/models/claim-beginning.js @@ -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 => { diff --git a/modules/claim/back/models/claim-beginning.json b/modules/claim/back/models/claim-beginning.json index afa21f817..d355881e8 100644 --- a/modules/claim/back/models/claim-beginning.json +++ b/modules/claim/back/models/claim-beginning.json @@ -1,11 +1,6 @@ { "name": "ClaimBeginning", "base": "Loggable", - "log": { - "model": "ClaimLog", - "relation": "claim", - "showField": "quantity" - }, "options": { "mysql": { "table": "claimBeginning" diff --git a/modules/claim/back/models/claim-development.json b/modules/claim/back/models/claim-development.json index 02061fab7..b0f352f50 100644 --- a/modules/claim/back/models/claim-development.json +++ b/modules/claim/back/models/claim-development.json @@ -1,10 +1,6 @@ { "name": "ClaimDevelopment", "base": "Loggable", - "log": { - "model": "ClaimLog", - "relation": "claim" - }, "options": { "mysql": { "table": "claimDevelopment" diff --git a/modules/claim/back/models/claim-dms.json b/modules/claim/back/models/claim-dms.json index a215b6bb7..26c90fd69 100644 --- a/modules/claim/back/models/claim-dms.json +++ b/modules/claim/back/models/claim-dms.json @@ -1,18 +1,14 @@ { "name": "ClaimDms", "base": "Loggable", - "log": { - "model": "ClaimLog", - "relation": "claim" - }, "options": { "mysql": { "table": "claimDms" } }, "allowedContentTypes": [ - "image/png", - "image/jpeg", + "image/png", + "image/jpeg", "image/jpg" ], "properties": { @@ -34,4 +30,4 @@ "foreignKey": "dmsFk" } } -} \ No newline at end of file +} diff --git a/modules/claim/back/models/claim-end.json b/modules/claim/back/models/claim-end.json index 12d79f71b..9f12ff93a 100644 --- a/modules/claim/back/models/claim-end.json +++ b/modules/claim/back/models/claim-end.json @@ -1,10 +1,6 @@ { "name": "ClaimEnd", "base": "Loggable", - "log": { - "model": "ClaimLog", - "relation": "claim" - }, "options": { "mysql": { "table": "claimEnd" diff --git a/modules/claim/back/models/claim-observation.json b/modules/claim/back/models/claim-observation.json index e882ad09d..2d418b76e 100644 --- a/modules/claim/back/models/claim-observation.json +++ b/modules/claim/back/models/claim-observation.json @@ -1,10 +1,6 @@ { "name": "ClaimObservation", "base": "Loggable", - "log": { - "model": "ClaimLog", - "relation": "claim" - }, "options": { "mysql": { "table": "claimObservation" @@ -40,4 +36,4 @@ "foreignKey": "claimFk" } } -} \ No newline at end of file +} diff --git a/modules/claim/back/models/claim-state.json b/modules/claim/back/models/claim-state.json index 2fd6d4845..f5bde4168 100644 --- a/modules/claim/back/models/claim-state.json +++ b/modules/claim/back/models/claim-state.json @@ -1,11 +1,6 @@ { "name": "ClaimState", "base": "Loggable", - "log": { - "model": "ClaimLog", - "relation": "claim", - "showField": "description" - }, "options": { "mysql": { "table": "claimState" diff --git a/modules/claim/back/models/claim.json b/modules/claim/back/models/claim.json index cd5b767e4..a7db1f3e1 100644 --- a/modules/claim/back/models/claim.json +++ b/modules/claim/back/models/claim.json @@ -1,10 +1,6 @@ { "name": "Claim", "base": "Loggable", - "log": { - "model": "ClaimLog", - "showField": "id" - }, "options": { "mysql": { "table": "claim" @@ -82,6 +78,11 @@ "type": "hasMany", "model": "ClaimDms", "foreignKey": "claimFk" + }, + "lines": { + "type": "hasMany", + "model": "ClaimBeginning", + "foreignKey": "claimFk" } } } diff --git a/modules/claim/front/descriptor/index.html b/modules/claim/front/descriptor/index.html index f346ecf17..5fd198440 100644 --- a/modules/claim/front/descriptor/index.html +++ b/modules/claim/front/descriptor/index.html @@ -86,7 +86,20 @@ icon="icon-ticket"> -
+
+ + +
+
+ + +
diff --git a/modules/claim/front/detail/index.js b/modules/claim/front/detail/index.js index 833519579..56f39e074 100644 --- a/modules/claim/front/detail/index.js +++ b/modules/claim/front/detail/index.js @@ -151,7 +151,7 @@ class Controller extends Section { isClaimEditable() { if (!this.claim) return; - this.$http.get(`ClaimStates/${this.claim.id}/isEditable`).then(res => { + this.$http.get(`ClaimStates/${this.claim.claimStateFk}/isEditable`).then(res => { this.isRewritable = res.data; }); } diff --git a/modules/claim/front/detail/index.spec.js b/modules/claim/front/detail/index.spec.js index 8f3049339..1ef779fd7 100644 --- a/modules/claim/front/detail/index.spec.js +++ b/modules/claim/front/detail/index.spec.js @@ -22,7 +22,8 @@ describe('claim', () => { controller = $componentController('vnClaimDetail', {$element, $scope}); controller.claim = { ticketFk: 1, - id: 2} + id: 2, + claimStateFk: 2} ; controller.salesToClaim = [{saleFk: 1}, {saleFk: 2}]; controller.salesClaimed = [{id: 1, sale: {}}]; diff --git a/modules/claim/front/locale/es.yml b/modules/claim/front/locale/es.yml index 5abdc1535..419e62f56 100644 --- a/modules/claim/front/locale/es.yml +++ b/modules/claim/front/locale/es.yml @@ -18,3 +18,5 @@ Claim deleted!: Reclamación eliminada! claim: reclamación Photos: Fotos Go to the claim: Ir a la reclamación +Sale tracking: Líneas preparadas +Ticket tracking: Estados del ticket diff --git a/modules/client/back/methods/client/campaignMetricsEmail.js b/modules/client/back/methods/client/campaignMetricsEmail.js index bb57f90a0..3a1bac5e6 100644 --- a/modules/client/back/methods/client/campaignMetricsEmail.js +++ b/modules/client/back/methods/client/campaignMetricsEmail.js @@ -51,19 +51,5 @@ module.exports = Self => { } }); - Self.campaignMetricsEmail = async ctx => { - 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('campaign-metrics', params); - - return email.send(); - }; + Self.campaignMetricsEmail = ctx => Self.sendTemplate(ctx, 'campaign-metrics'); }; diff --git a/modules/client/back/methods/client/campaignMetricsPdf.js b/modules/client/back/methods/client/campaignMetricsPdf.js index 14194d62b..e163b0619 100644 --- a/modules/client/back/methods/client/campaignMetricsPdf.js +++ b/modules/client/back/methods/client/campaignMetricsPdf.js @@ -1,5 +1,3 @@ -const {Report} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('campaignMetricsPdf', { description: 'Returns the campaign metrics pdf', @@ -50,17 +48,5 @@ module.exports = Self => { } }); - Self.campaignMetricsPdf = 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('campaign-metrics', params); - const stream = await report.toPdfStream(); - - return [stream, 'application/pdf', `filename="doc-${id}.pdf"`]; - }; + Self.campaignMetricsPdf = (ctx, id) => Self.printReport(ctx, id, 'campaign-metrics'); }; diff --git a/modules/client/back/methods/client/checkDuplicated.js b/modules/client/back/methods/client/checkDuplicated.js deleted file mode 100644 index 522cd088f..000000000 --- a/modules/client/back/methods/client/checkDuplicated.js +++ /dev/null @@ -1,63 +0,0 @@ -module.exports = Self => { - Self.remoteMethod('checkDuplicatedData', { - description: 'Checks if a client has same email, mobile or phone than other client and send an email', - accepts: [{ - arg: 'id', - type: 'number', - required: true, - description: 'The client id' - }], - returns: { - type: 'object', - root: true - }, - http: { - verb: 'GET', - path: '/:id/checkDuplicatedData' - } - }); - - Self.checkDuplicatedData = async function(id, options) { - const myOptions = {}; - - if (typeof options == 'object') - Object.assign(myOptions, options); - - const client = await Self.app.models.Client.findById(id, myOptions); - - const findParams = []; - if (client.email) { - const emails = client.email.split(','); - for (let email of emails) - findParams.push({email: email}); - } - - if (client.phone) - findParams.push({phone: client.phone}); - - if (client.mobile) - findParams.push({mobile: client.mobile}); - - const filterObj = { - where: { - and: [ - {or: findParams}, - {id: {neq: client.id}} - ] - } - }; - - const clientSameData = await Self.findOne(filterObj, myOptions); - - if (clientSameData) { - await Self.app.models.Mail.create({ - receiver: 'direccioncomercial@verdnatura.es', - subject: `Cliente con email/teléfono/móvil duplicados`, - body: 'El cliente ' + client.id + ' comparte alguno de estos datos con el cliente ' + clientSameData.id + - '\n- Email: ' + client.email + - '\n- Teléfono: ' + client.phone + - '\n- Móvil: ' + client.mobile - }, myOptions); - } - }; -}; diff --git a/modules/client/back/methods/client/clientDebtStatementEmail.js b/modules/client/back/methods/client/clientDebtStatementEmail.js index 8bcdc900f..1b3ab13d8 100644 --- a/modules/client/back/methods/client/clientDebtStatementEmail.js +++ b/modules/client/back/methods/client/clientDebtStatementEmail.js @@ -46,19 +46,5 @@ module.exports = Self => { } }); - Self.clientDebtStatementEmail = async ctx => { - 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('client-debt-statement', params); - - return email.send(); - }; + Self.clientDebtStatementEmail = ctx => Self.sendTemplate(ctx, 'client-debt-statement'); }; diff --git a/modules/client/back/methods/client/clientDebtStatementHtml.js b/modules/client/back/methods/client/clientDebtStatementHtml.js index bfed696bc..8752b48d2 100644 --- a/modules/client/back/methods/client/clientDebtStatementHtml.js +++ b/modules/client/back/methods/client/clientDebtStatementHtml.js @@ -1,5 +1,3 @@ -const {Email} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('clientDebtStatementHtml', { description: 'Returns the client debt statement email preview', @@ -45,21 +43,5 @@ module.exports = Self => { } }); - Self.clientDebtStatementHtml = async(ctx, id) => { - 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('client-debt-statement', params); - const html = await report.render(); - - return [html, 'text/html', `filename="mail-${id}.pdf"`]; - }; + Self.clientDebtStatementHtml = (ctx, id) => Self.printEmail(ctx, id, 'client-debt-statement'); }; diff --git a/modules/client/back/methods/client/clientDebtStatementPdf.js b/modules/client/back/methods/client/clientDebtStatementPdf.js index 8e2dca314..845527ace 100644 --- a/modules/client/back/methods/client/clientDebtStatementPdf.js +++ b/modules/client/back/methods/client/clientDebtStatementPdf.js @@ -1,5 +1,3 @@ -const {Report} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('clientDebtStatementPdf', { description: 'Returns the client debt statement pdf', @@ -45,17 +43,5 @@ module.exports = Self => { } }); - Self.clientDebtStatementPdf = 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('client-debt-statement', params); - const stream = await report.toPdfStream(); - - return [stream, 'application/pdf', `filename="doc-${id}.pdf"`]; - }; + Self.clientDebtStatementPdf = (ctx, id) => Self.printReport(ctx, id, 'client-debt-statement'); }; diff --git a/modules/client/back/methods/client/clientWelcomeEmail.js b/modules/client/back/methods/client/clientWelcomeEmail.js index 318ee18e6..accf12bb8 100644 --- a/modules/client/back/methods/client/clientWelcomeEmail.js +++ b/modules/client/back/methods/client/clientWelcomeEmail.js @@ -1,5 +1,3 @@ -const {Email} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('clientWelcomeEmail', { description: 'Sends the client welcome email with an attached PDF', @@ -41,19 +39,5 @@ module.exports = Self => { } }); - Self.clientWelcomeEmail = async ctx => { - 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('client-welcome', params); - - return email.send(); - }; + Self.clientWelcomeEmail = ctx => Self.sendTemplate(ctx, 'client-welcome'); }; diff --git a/modules/client/back/methods/client/clientWelcomeHtml.js b/modules/client/back/methods/client/clientWelcomeHtml.js index dfb560326..093a06d8e 100644 --- a/modules/client/back/methods/client/clientWelcomeHtml.js +++ b/modules/client/back/methods/client/clientWelcomeHtml.js @@ -1,5 +1,3 @@ -const {Email} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('clientWelcomeHtml', { description: 'Returns the client welcome email preview', @@ -40,19 +38,5 @@ module.exports = Self => { } }); - Self.clientWelcomeHtml = 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]; - - params.isPreview = true; - - const report = new Email('client-welcome', params); - const html = await report.render(); - - return [html, 'text/html', `filename="mail-${id}.pdf"`]; - }; + Self.clientWelcomeHtml = (ctx, id) => Self.printEmail(ctx, id, 'client-welcome'); }; diff --git a/modules/client/back/methods/client/creditRequestEmail.js b/modules/client/back/methods/client/creditRequestEmail.js index b6a60e971..0255949e0 100644 --- a/modules/client/back/methods/client/creditRequestEmail.js +++ b/modules/client/back/methods/client/creditRequestEmail.js @@ -1,5 +1,3 @@ -const {Email} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('clientCreditEmail', { description: 'Sends the credit request email with an attached PDF', @@ -10,7 +8,7 @@ module.exports = Self => { type: 'number', required: true, description: 'The client id', - http: {source: 'path'} + http: {source: 'path'}, }, { arg: 'recipient', @@ -22,38 +20,25 @@ module.exports = Self => { arg: 'replyTo', type: 'string', description: 'The sender email to reply to', - required: false + required: false, }, { arg: 'recipientId', type: 'number', - description: 'The recipient id to send to the recipient preferred language', - required: false - } + description: + 'The recipient id to send to the recipient preferred language', + required: false, + }, ], returns: { type: ['object'], - root: true + root: true, }, http: { path: '/:id/credit-request-email', - verb: 'POST' - } + verb: 'POST', + }, }); - Self.clientCreditEmail = async ctx => { - 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('credit-request', params); - - return email.send(); - }; + Self.clientCreditEmail = ctx => Self.sendTemplate(ctx, 'credit-request'); }; diff --git a/modules/client/back/methods/client/creditRequestHtml.js b/modules/client/back/methods/client/creditRequestHtml.js index 6b2d7fe4e..fbd6cacb9 100644 --- a/modules/client/back/methods/client/creditRequestHtml.js +++ b/modules/client/back/methods/client/creditRequestHtml.js @@ -1,5 +1,3 @@ -const {Email} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('creditRequestHtml', { description: 'Returns the credit request email preview', @@ -40,21 +38,5 @@ module.exports = Self => { } }); - Self.creditRequestHtml = async(ctx, id) => { - 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('credit-request', params); - const html = await report.render(); - - return [html, 'text/html', `filename="mail-${id}.pdf"`]; - }; + Self.creditRequestHtml = (ctx, id) => Self.printEmail(ctx, id, 'credit-request'); }; diff --git a/modules/client/back/methods/client/creditRequestPdf.js b/modules/client/back/methods/client/creditRequestPdf.js index 2e3dc0619..a4f4ed128 100644 --- a/modules/client/back/methods/client/creditRequestPdf.js +++ b/modules/client/back/methods/client/creditRequestPdf.js @@ -1,5 +1,3 @@ -const {Report} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('creditRequestPdf', { description: 'Returns the credit request pdf', @@ -40,17 +38,5 @@ module.exports = Self => { } }); - Self.creditRequestPdf = 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('credit-request', params); - const stream = await report.toPdfStream(); - - return [stream, 'application/pdf', `filename="doc-${id}.pdf"`]; - }; + Self.creditRequestPdf = (ctx, id) => Self.printReport(ctx, id, 'credit-request'); }; diff --git a/modules/client/back/methods/client/extendedListFilter.js b/modules/client/back/methods/client/extendedListFilter.js index 8e02cd413..27bbe2a35 100644 --- a/modules/client/back/methods/client/extendedListFilter.js +++ b/modules/client/back/methods/client/extendedListFilter.js @@ -97,7 +97,7 @@ module.exports = Self => { const stmts = []; const stmt = new ParameterizedSQL( - `SELECT + `SELECT c.id, c.name, c.socialName, diff --git a/modules/client/back/methods/client/getCard.js b/modules/client/back/methods/client/getCard.js index 99c59f757..a2365ee25 100644 --- a/modules/client/back/methods/client/getCard.js +++ b/modules/client/back/methods/client/getCard.js @@ -80,7 +80,7 @@ module.exports = function(Self) { const data = await Self.rawSql(query, [id, date], myOptions); client.debt = data[0].debt; - client.unpaid = await Self.app.models.ClientUnpaid.findOne({id}, myOptions); + client.unpaid = await Self.app.models.ClientUnpaid.findById(id, null, myOptions); return client; }; diff --git a/modules/client/back/methods/client/getTransactions.js b/modules/client/back/methods/client/getTransactions.js deleted file mode 100644 index 45183bbdc..000000000 --- a/modules/client/back/methods/client/getTransactions.js +++ /dev/null @@ -1,49 +0,0 @@ - -const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; - -module.exports = Self => { - Self.remoteMethod('getTransactions', { - description: 'Returns last entries', - accessType: 'READ', - accepts: [{ - arg: 'filter', - type: 'object', - description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string', - http: {source: 'query'} - }], - returns: { - type: ['object'], - root: true - }, - http: { - path: `/getTransactions`, - verb: 'GET' - } - }); - - Self.getTransactions = async(filter, options) => { - const myOptions = {}; - - if (typeof options == 'object') - Object.assign(myOptions, options); - - const conn = Self.dataSource.connector; - const stmt = new ParameterizedSQL(` - SELECT - t.id, - t.clientFk, - t.created, - t.amount / 100 amount, - t.receiptFk IS NOT NULL AS isConfirmed, - tt.message responseMessage, - te.message errorMessage - FROM hedera.tpvTransaction t - JOIN hedera.tpvMerchant m ON m.id = t.merchantFk - LEFT JOIN hedera.tpvResponse tt ON tt.id = t.response - LEFT JOIN hedera.tpvError te ON te.code = errorCode`); - - stmt.merge(conn.makeSuffix(filter, 't')); - - return Self.rawStmt(stmt, myOptions); - }; -}; diff --git a/modules/client/back/methods/client/incotermsAuthorizationEmail.js b/modules/client/back/methods/client/incotermsAuthorizationEmail.js index 2a4fe593a..4a21f20b0 100644 --- a/modules/client/back/methods/client/incotermsAuthorizationEmail.js +++ b/modules/client/back/methods/client/incotermsAuthorizationEmail.js @@ -1,5 +1,3 @@ -const {Email} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('incotermsAuthorizationEmail', { description: 'Sends the incoterms authorization email with an attached PDF', @@ -47,19 +45,5 @@ module.exports = Self => { } }); - Self.incotermsAuthorizationEmail = async ctx => { - 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('incoterms-authorization', params); - - return email.send(); - }; + Self.incotermsAuthorizationEmail = ctx => Self.sendTemplate(ctx, 'incoterms-authorization'); }; diff --git a/modules/client/back/methods/client/incotermsAuthorizationHtml.js b/modules/client/back/methods/client/incotermsAuthorizationHtml.js index 875495d93..0a6bba0a8 100644 --- a/modules/client/back/methods/client/incotermsAuthorizationHtml.js +++ b/modules/client/back/methods/client/incotermsAuthorizationHtml.js @@ -1,5 +1,3 @@ -const {Email} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('incotermsAuthorizationHtml', { description: 'Returns the incoterms authorization email preview', @@ -46,21 +44,5 @@ module.exports = Self => { } }); - Self.incotermsAuthorizationHtml = async(ctx, id) => { - 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('incoterms-authorization', params); - const html = await report.render(); - - return [html, 'text/html', `filename="mail-${id}.pdf"`]; - }; + Self.incotermsAuthorizationHtml = (ctx, id) => Self.printEmail(ctx, id, 'incoterms-authorization'); }; diff --git a/modules/client/back/methods/client/incotermsAuthorizationPdf.js b/modules/client/back/methods/client/incotermsAuthorizationPdf.js index 9a8a8d296..d37e473f1 100644 --- a/modules/client/back/methods/client/incotermsAuthorizationPdf.js +++ b/modules/client/back/methods/client/incotermsAuthorizationPdf.js @@ -1,5 +1,3 @@ -const {Report} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('incotermsAuthorizationPdf', { description: 'Returns the incoterms authorization pdf', @@ -46,17 +44,5 @@ module.exports = Self => { } }); - Self.incotermsAuthorizationPdf = 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('incoterms-authorization', params); - const stream = await report.toPdfStream(); - - return [stream, 'application/pdf', `filename="doc-${id}.pdf"`]; - }; + Self.incotermsAuthorizationPdf = (ctx, id) => Self.printReport(ctx, id, 'incoterms-authorization'); }; diff --git a/modules/client/back/methods/client/letterDebtorNdEmail.js b/modules/client/back/methods/client/letterDebtorNdEmail.js index e188c6e0a..396acdb97 100644 --- a/modules/client/back/methods/client/letterDebtorNdEmail.js +++ b/modules/client/back/methods/client/letterDebtorNdEmail.js @@ -1,5 +1,3 @@ -const {Email} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('letterDebtorNdEmail', { description: 'Sends the second debtor letter email with an attached PDF', @@ -47,19 +45,5 @@ module.exports = Self => { } }); - Self.letterDebtorNdEmail = async ctx => { - 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('letter-debtor-nd', params); - - return email.send(); - }; + Self.letterDebtorNdEmail = ctx => Self.sendTemplate(ctx, 'letter-debtor-nd'); }; diff --git a/modules/client/back/methods/client/letterDebtorNdHtml.js b/modules/client/back/methods/client/letterDebtorNdHtml.js index 320fbaef3..f14f96dea 100644 --- a/modules/client/back/methods/client/letterDebtorNdHtml.js +++ b/modules/client/back/methods/client/letterDebtorNdHtml.js @@ -1,5 +1,3 @@ -const {Email} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('letterDebtorNdHtml', { description: 'Returns the second letter debtor email preview', @@ -46,21 +44,5 @@ module.exports = Self => { } }); - Self.letterDebtorNdHtml = async(ctx, id) => { - 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('letter-debtor-nd', params); - const html = await report.render(); - - return [html, 'text/html', `filename="mail-${id}.pdf"`]; - }; + Self.letterDebtorNdHtml = (ctx, id) => Self.printEmail(ctx, id, 'letter-debtor-nd'); }; diff --git a/modules/client/back/methods/client/letterDebtorPdf.js b/modules/client/back/methods/client/letterDebtorPdf.js index 421d531e6..943869143 100644 --- a/modules/client/back/methods/client/letterDebtorPdf.js +++ b/modules/client/back/methods/client/letterDebtorPdf.js @@ -1,5 +1,3 @@ -const {Report} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('letterDebtorPdf', { description: 'Returns the letter debtor pdf', @@ -46,17 +44,5 @@ module.exports = Self => { } }); - Self.letterDebtorPdf = 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('letter-debtor', params); - const stream = await report.toPdfStream(); - - return [stream, 'application/pdf', `filename="doc-${id}.pdf"`]; - }; + Self.letterDebtorPdf = (ctx, id) => Self.printReport(ctx, id, 'letter-debtor'); }; diff --git a/modules/client/back/methods/client/letterDebtorStEmail.js b/modules/client/back/methods/client/letterDebtorStEmail.js index ee39a101b..c76204fbc 100644 --- a/modules/client/back/methods/client/letterDebtorStEmail.js +++ b/modules/client/back/methods/client/letterDebtorStEmail.js @@ -1,5 +1,3 @@ -const {Email} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('letterDebtorStEmail', { description: 'Sends the printer setup email with an attached PDF', @@ -47,19 +45,5 @@ module.exports = Self => { } }); - Self.letterDebtorStEmail = async ctx => { - 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('letter-debtor-st', params); - - return email.send(); - }; + Self.letterDebtorStEmail = ctx => Self.sendTemplate(ctx, 'letter-debtor-st'); }; diff --git a/modules/client/back/methods/client/letterDebtorStHtml.js b/modules/client/back/methods/client/letterDebtorStHtml.js index acf75272b..a1dcf00d7 100644 --- a/modules/client/back/methods/client/letterDebtorStHtml.js +++ b/modules/client/back/methods/client/letterDebtorStHtml.js @@ -1,5 +1,3 @@ -const {Email} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('letterDebtorStHtml', { description: 'Returns the letter debtor email preview', @@ -46,21 +44,5 @@ module.exports = Self => { } }); - Self.letterDebtorStHtml = async(ctx, id) => { - 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('letter-debtor-st', params); - const html = await report.render(); - - return [html, 'text/html', `filename="mail-${id}.pdf"`]; - }; + Self.letterDebtorStHtml = (ctx, id) => Self.printEmail(ctx, id, 'letter-debtor-st'); }; diff --git a/modules/client/back/methods/client/printerSetupEmail.js b/modules/client/back/methods/client/printerSetupEmail.js index 254948659..2a0903e90 100644 --- a/modules/client/back/methods/client/printerSetupEmail.js +++ b/modules/client/back/methods/client/printerSetupEmail.js @@ -1,5 +1,3 @@ -const {Email} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('printerSetupEmail', { description: 'Sends the printer setup email with an attached PDF', @@ -41,19 +39,5 @@ module.exports = Self => { } }); - Self.printerSetupEmail = async ctx => { - 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('printer-setup', params); - - return email.send(); - }; + Self.printerSetupEmail = ctx => Self.sendTemplate(ctx, 'printer-setup'); }; diff --git a/modules/client/back/methods/client/printerSetupHtml.js b/modules/client/back/methods/client/printerSetupHtml.js index 1ef1843e0..c9d94d1c2 100644 --- a/modules/client/back/methods/client/printerSetupHtml.js +++ b/modules/client/back/methods/client/printerSetupHtml.js @@ -1,5 +1,3 @@ -const {Email} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('printerSetupHtml', { description: 'Returns the printer setup email preview', @@ -40,19 +38,5 @@ module.exports = Self => { } }); - Self.printerSetupHtml = 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]; - - params.isPreview = true; - - const report = new Email('printer-setup', params); - const html = await report.render(); - - return [html, 'text/html', `filename="mail-${id}.pdf"`]; - }; + Self.printerSetupHtml = (ctx, id) => Self.printEmail(ctx, id, 'printer-setup'); }; diff --git a/modules/client/back/methods/client/sepaCoreEmail.js b/modules/client/back/methods/client/sepaCoreEmail.js index 93c9d4302..20931eb03 100644 --- a/modules/client/back/methods/client/sepaCoreEmail.js +++ b/modules/client/back/methods/client/sepaCoreEmail.js @@ -1,5 +1,3 @@ -const {Email} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('sepaCoreEmail', { description: 'Sends the campaign metrics email with an attached PDF', @@ -47,19 +45,5 @@ module.exports = Self => { } }); - Self.sepaCoreEmail = async ctx => { - 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('sepa-core', params); - - return email.send(); - }; + Self.sepaCoreEmail = ctx => Self.sendTemplate(ctx, 'sepa-core'); }; diff --git a/modules/client/back/methods/client/specs/checkDuplicated.spec.js b/modules/client/back/methods/client/specs/checkDuplicated.spec.js deleted file mode 100644 index 1b682ca35..000000000 --- a/modules/client/back/methods/client/specs/checkDuplicated.spec.js +++ /dev/null @@ -1,24 +0,0 @@ -const models = require('vn-loopback/server/server').models; - -describe('client checkDuplicated()', () => { - it('should send an mail if mobile/phone/email is duplicated', async() => { - const tx = await models.Client.beginTransaction({}); - - try { - const options = {transaction: tx}; - - const id = 1110; - const mailModel = models.Mail; - spyOn(mailModel, 'create'); - - await models.Client.checkDuplicatedData(id, options); - - expect(mailModel.create).toHaveBeenCalled(); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - throw e; - } - }); -}); diff --git a/modules/client/back/methods/client/specs/getTransactions.spec.js b/modules/client/back/methods/client/specs/getTransactions.spec.js deleted file mode 100644 index 0387eb59a..000000000 --- a/modules/client/back/methods/client/specs/getTransactions.spec.js +++ /dev/null @@ -1,21 +0,0 @@ -const models = require('vn-loopback/server/server').models; - -describe('Client getTransations', () => { - it('should call getTransations() method to receive a list of Web Payments from Bruce Wayne', async() => { - const tx = await models.Client.beginTransaction({}); - - try { - const options = {transaction: tx}; - - const filter = {where: {clientFk: 1101}}; - const result = await models.Client.getTransactions(filter, options); - - expect(result[1].id).toBeTruthy(); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - throw e; - } - }); -}); diff --git a/modules/client/back/methods/client/specs/transactions.spec.js b/modules/client/back/methods/client/specs/transactions.spec.js new file mode 100644 index 000000000..b4af40195 --- /dev/null +++ b/modules/client/back/methods/client/specs/transactions.spec.js @@ -0,0 +1,66 @@ +const models = require('vn-loopback/server/server').models; + +describe('Client transactions', () => { + it('should call transactions() method to receive a list of Web Payments from Bruce Wayne', async() => { + const tx = await models.Client.beginTransaction({}); + + try { + const options = {transaction: tx}; + + const ctx = {}; + const filter = {where: {clientFk: 1101}}; + const result = await models.Client.transactions(ctx, filter, options); + + expect(result[1].id).toBeTruthy(); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + + it('should call transactions() method filtering by orderFk', async() => { + const tx = await models.Client.beginTransaction({}); + + try { + const options = {transaction: tx}; + + const ctx = {args: {orderFk: 6}}; + const filter = {}; + const result = await models.Client.transactions(ctx, filter, options); + + const firstRow = result[0]; + + expect(result.length).toEqual(1); + expect(firstRow.id).toEqual(6); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + + it('should call transactions() method filtering by amount', async() => { + const tx = await models.Client.beginTransaction({}); + + try { + const options = {transaction: tx}; + + const ctx = {args: {amount: 40}}; + const filter = {}; + const result = await models.Client.transactions(ctx, filter, options); + + const randomIndex = Math.floor(Math.random() * result.length); + const transaction = result[randomIndex]; + + expect(transaction.amount).toEqual(40); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); +}); diff --git a/modules/client/back/methods/client/transactions.js b/modules/client/back/methods/client/transactions.js new file mode 100644 index 000000000..691910721 --- /dev/null +++ b/modules/client/back/methods/client/transactions.js @@ -0,0 +1,84 @@ + +const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; +const buildFilter = require('vn-loopback/util/filter').buildFilter; +const mergeFilters = require('vn-loopback/util/filter').mergeFilters; + +module.exports = Self => { + Self.remoteMethodCtx('transactions', { + description: 'Returns customer transactions', + accessType: 'READ', + accepts: [ + { + arg: 'filter', + type: 'object', + description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string', + http: {source: 'query'} + }, + { + arg: 'orderFk', + type: 'number', + http: {source: 'query'} + }, + { + arg: 'clientFk', + type: 'number', + http: {source: 'query'} + }, + { + arg: 'amount', + type: 'number', + http: {source: 'query'} + } + ], + returns: { + type: ['object'], + root: true + }, + http: { + path: `/transactions`, + verb: 'GET' + } + }); + + Self.transactions = async(ctx, filter, options) => { + const args = ctx.args; + const myOptions = {}; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + const where = buildFilter(args, (param, value) => { + switch (param) { + case 'orderFk': + return {'t.id': value}; + case 'clientFk': + return {'t.clientFk': value}; + case 'amount': + return {'t.amount': (value * 100)}; + } + }); + + filter = mergeFilters(filter, {where}); + + const conn = Self.dataSource.connector; + const stmt = new ParameterizedSQL(` + SELECT + t.id, + t.clientFk, + c.name AS customerName, + t.created, + t.amount / 100 amount, + t.receiptFk IS NOT NULL AS isConfirmed, + tt.message responseMessage, + te.message errorMessage + FROM hedera.tpvTransaction t + JOIN client c ON c.id = t.clientFk + JOIN hedera.tpvMerchant m ON m.id = t.merchantFk + LEFT JOIN hedera.tpvResponse tt ON tt.id = t.response + LEFT JOIN hedera.tpvError te ON te.code = errorCode`); + + stmt.merge(conn.makeSuffix(filter, 't')); + + return Self.rawStmt(stmt, myOptions); + }; +}; diff --git a/modules/client/back/methods/defaulter/observationEmail.js b/modules/client/back/methods/defaulter/observationEmail.js new file mode 100644 index 000000000..c3c96010e --- /dev/null +++ b/modules/client/back/methods/defaulter/observationEmail.js @@ -0,0 +1,52 @@ +module.exports = Self => { + Self.remoteMethodCtx('observationEmail', { + description: 'Send an email with the observation', + accessType: 'WRITE', + accepts: [ + { + arg: 'defaulters', + type: ['object'], + required: true, + description: 'The defaulters to send the email' + }, + { + arg: 'observation', + type: 'string', + required: true, + description: 'The observation' + }], + returns: { + arg: 'observationEmail' + }, + http: { + path: `/observationEmail`, + verb: 'POST' + } + }); + + Self.observationEmail = async(ctx, defaulters, observation, options) => { + const models = Self.app.models; + const $t = ctx.req.__; // $translate + const myOptions = {}; + const userId = ctx.req.accessToken.userId; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + for (const defaulter of defaulters) { + const user = await models.Account.findById(userId, {fields: ['name']}, myOptions); + + const body = $t('Added observation', { + user: user.name, + text: observation + }); + + await models.Mail.create({ + subject: $t('Comment added to client', {clientFk: defaulter.clientFk}), + body: body, + receiver: `${defaulter.salesPersonName}@verdnatura.es`, + replyTo: `${user.name}@verdnatura.es` + }, myOptions); + } + }; +}; diff --git a/modules/client/back/methods/receipt/balanceCompensationPdf.js b/modules/client/back/methods/receipt/balanceCompensationPdf.js index ff8713253..e790d54a1 100644 --- a/modules/client/back/methods/receipt/balanceCompensationPdf.js +++ b/modules/client/back/methods/receipt/balanceCompensationPdf.js @@ -1,5 +1,3 @@ -const { Report } = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('balanceCompensationPdf', { description: 'Returns the the debit balances compensation pdf', @@ -10,7 +8,7 @@ module.exports = Self => { type: 'number', required: true, description: 'The receipt id', - http: { source: 'path' } + http: {source: 'path'} } ], returns: [ @@ -34,17 +32,5 @@ module.exports = Self => { } }); - Self.balanceCompensationPdf = 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('balance-compensation', params); - const stream = await report.toPdfStream(); - - return [stream, 'application/pdf', `filename="doc-${id}.pdf"`]; - }; + Self.balanceCompensationPdf = (ctx, id) => Self.printReport(ctx, id, 'balance-compensation'); }; diff --git a/modules/client/back/methods/receipt/receiptPdf.js b/modules/client/back/methods/receipt/receiptPdf.js index f55e05040..433f386db 100644 --- a/modules/client/back/methods/receipt/receiptPdf.js +++ b/modules/client/back/methods/receipt/receiptPdf.js @@ -1,5 +1,3 @@ -const {Report} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('receiptPdf', { description: 'Returns the receipt pdf', @@ -39,17 +37,5 @@ module.exports = Self => { } }); - Self.receiptPdf = 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('receipt', params); - const stream = await report.toPdfStream(); - - return [stream, 'application/pdf', `filename="doc-${id}.pdf"`]; - }; + Self.receiptPdf = (ctx, id) => Self.printReport(ctx, id, 'receipt'); }; diff --git a/modules/client/back/models/address.json b/modules/client/back/models/address.json index 0dcbbf7fe..5f962677d 100644 --- a/modules/client/back/models/address.json +++ b/modules/client/back/models/address.json @@ -2,11 +2,6 @@ "name": "Address", "description": "Client addresses", "base": "Loggable", - "log": { - "model": "ClientLog", - "relation": "client", - "showField": "nickname" - }, "options": { "mysql": { "table": "address" @@ -88,4 +83,4 @@ "foreignKey": "customsAgentFk" } } -} \ No newline at end of file +} diff --git a/modules/client/back/models/client-contact.json b/modules/client/back/models/client-contact.json index 514ebbf5e..3f71ab79e 100644 --- a/modules/client/back/models/client-contact.json +++ b/modules/client/back/models/client-contact.json @@ -2,11 +2,6 @@ "name": "ClientContact", "description": "Client phone contacts", "base": "Loggable", - "log": { - "model": "ClientLog", - "relation": "client", - "showField": "name" - }, "options": { "mysql": { "table": "clientContact" @@ -33,4 +28,4 @@ "foreignKey": "clientFk" } } -} \ No newline at end of file +} diff --git a/modules/client/back/models/client-dms.json b/modules/client/back/models/client-dms.json index 88b4349df..14b19498e 100644 --- a/modules/client/back/models/client-dms.json +++ b/modules/client/back/models/client-dms.json @@ -1,11 +1,6 @@ { "name": "ClientDms", "base": "Loggable", - "log": { - "model":"ClientLog", - "relation": "client", - "showField": "dmsFk" - }, "options": { "mysql": { "table": "clientDms" diff --git a/modules/client/back/models/client-methods.js b/modules/client/back/models/client-methods.js index 9241d80cf..3538dbeb8 100644 --- a/modules/client/back/models/client-methods.js +++ b/modules/client/back/models/client-methods.js @@ -2,7 +2,6 @@ module.exports = Self => { require('../methods/client/addressesPropagateRe')(Self); require('../methods/client/canBeInvoiced')(Self); require('../methods/client/canCreateTicket')(Self); - require('../methods/client/checkDuplicated')(Self); require('../methods/client/confirmTransaction')(Self); require('../methods/client/consumption')(Self); require('../methods/client/createAddress')(Self); @@ -13,7 +12,7 @@ module.exports = Self => { require('../methods/client/getCard')(Self); require('../methods/client/getDebt')(Self); require('../methods/client/getMana')(Self); - require('../methods/client/getTransactions')(Self); + require('../methods/client/transactions')(Self); require('../methods/client/hasCustomerRole')(Self); require('../methods/client/isValidClient')(Self); require('../methods/client/lastActiveTickets')(Self); diff --git a/modules/client/back/models/client-observation.json b/modules/client/back/models/client-observation.json index d3059377d..b8852b186 100644 --- a/modules/client/back/models/client-observation.json +++ b/modules/client/back/models/client-observation.json @@ -2,10 +2,6 @@ "name": "ClientObservation", "description": "Client notes", "base": "Loggable", - "log": { - "model": "ClientLog", - "relation": "client" - }, "options": { "mysql": { "table": "clientObservation" diff --git a/modules/client/back/models/client-sample.json b/modules/client/back/models/client-sample.json index fc64cd949..6430b66ae 100644 --- a/modules/client/back/models/client-sample.json +++ b/modules/client/back/models/client-sample.json @@ -1,11 +1,6 @@ { "name": "ClientSample", "base": "Loggable", - "log": { - "model": "ClientLog", - "relation": "client", - "showField": "type" - }, "options": { "mysql": { "table": "clientSample" diff --git a/modules/client/back/models/client.js b/modules/client/back/models/client.js index 2d8e7bd27..c41085b79 100644 --- a/modules/client/back/models/client.js +++ b/modules/client/back/models/client.js @@ -279,6 +279,18 @@ module.exports = Self => { // Credit changes if (changes.credit !== undefined) await Self.changeCredit(ctx, finalState, changes); + + const oldInstance = {}; + if (!ctx.isNewInstance) { + const newProps = Object.keys(changes); + Object.keys(orgData.__data).forEach(prop => { + if (newProps.includes(prop)) + oldInstance[prop] = orgData[prop]; + }); + } + + ctx.hookState.oldInstance = oldInstance; + ctx.hookState.newInstance = changes; }); Self.observe('after save', async ctx => { diff --git a/modules/client/back/models/client.json b/modules/client/back/models/client.json index 21db28eaf..6b40aff8e 100644 --- a/modules/client/back/models/client.json +++ b/modules/client/back/models/client.json @@ -1,10 +1,6 @@ { "name": "Client", "base": "Loggable", - "log": { - "model":"ClientLog", - "showField": "id" - }, "options": { "mysql": { "table": "client" @@ -260,4 +256,4 @@ } } } -} \ No newline at end of file +} diff --git a/modules/client/back/models/defaulter.js b/modules/client/back/models/defaulter.js index 13bb1a614..868d6cd0a 100644 --- a/modules/client/back/models/defaulter.js +++ b/modules/client/back/models/defaulter.js @@ -1,3 +1,4 @@ module.exports = Self => { require('../methods/defaulter/filter')(Self); + require('../methods/defaulter/observationEmail')(Self); }; diff --git a/modules/client/back/models/greuge.json b/modules/client/back/models/greuge.json index 625bf4e28..9cc056260 100644 --- a/modules/client/back/models/greuge.json +++ b/modules/client/back/models/greuge.json @@ -1,11 +1,6 @@ { "name": "Greuge", "base": "Loggable", - "log": { - "model": "ClientLog", - "relation": "client", - "showField": "description" - }, "options": { "mysql": { "table": "greuge" @@ -58,4 +53,4 @@ "foreignKey": "userFk" } } -} \ No newline at end of file +} diff --git a/modules/client/back/models/receipt.json b/modules/client/back/models/receipt.json index 19107f561..da7879df9 100644 --- a/modules/client/back/models/receipt.json +++ b/modules/client/back/models/receipt.json @@ -62,6 +62,11 @@ "type": "belongsTo", "model": "Bank", "foreignKey": "bankFk" + }, + "supplier": { + "type": "belongsTo", + "model": "Supplier", + "foreignKey": "companyFk" } } -} \ No newline at end of file +} diff --git a/modules/client/back/models/recovery.json b/modules/client/back/models/recovery.json index de4183924..5ea89197d 100644 --- a/modules/client/back/models/recovery.json +++ b/modules/client/back/models/recovery.json @@ -1,10 +1,6 @@ { "name": "Recovery", "base": "Loggable", - "log": { - "model": "ClientLog", - "relation": "client" - }, "options": { "mysql": { "table": "recovery" @@ -38,4 +34,4 @@ "foreignKey": "clientFk" } } -} \ No newline at end of file +} diff --git a/modules/client/front/basic-data/index.js b/modules/client/front/basic-data/index.js index b08d642d1..ed34eefc4 100644 --- a/modules/client/front/basic-data/index.js +++ b/modules/client/front/basic-data/index.js @@ -9,9 +9,7 @@ export default class Controller extends Section { } onSubmit() { - return this.$.watcher.submit().then(() => { - this.$http.get(`Clients/${this.$params.id}/checkDuplicatedData`); - }); + return this.$.watcher.submit(); } } diff --git a/modules/client/front/create/index.js b/modules/client/front/create/index.js index 9ca58ed10..631029802 100644 --- a/modules/client/front/create/index.js +++ b/modules/client/front/create/index.js @@ -12,7 +12,6 @@ export default class Controller extends Section { onSubmit() { return this.$.watcher.submit().then(json => { this.$state.go('client.card.basicData', {id: json.data.id}); - this.$http.get(`Clients/${this.client.id}/checkDuplicatedData`); }); } diff --git a/modules/client/front/defaulter/index.html b/modules/client/front/defaulter/index.html index 22b78594a..8f22629a9 100644 --- a/modules/client/front/defaulter/index.html +++ b/modules/client/front/defaulter/index.html @@ -5,6 +5,7 @@ limit="20" order="amount DESC" data="defaulters" + on-data-change="$ctrl.reCheck()" auto-load="true"> @@ -17,22 +18,22 @@ -
Total
-
- - @@ -56,25 +57,25 @@ Comercial - Balance D. - Author Last observation - L. O. Date - @@ -88,8 +89,9 @@ - @@ -150,7 +152,7 @@ - + @@ -160,7 +162,7 @@ id !== clientId) : [...this.checkedDefaulers, clientId]; + } + + reCheck() { + if (!this.$.model.data || !this.checkedDefaulers.length) return; + + this.$.model.data.forEach(defaulter => { + defaulter.checked = this.checkedDefaulers.includes(defaulter.clientFk); + }); + } + getBalanceDueTotal() { this.$http.get('Defaulters/filter') .then(res => { @@ -109,11 +123,20 @@ export default class Controller extends Section { } this.$http.post(`ClientObservations`, params) .then(() => { - this.vnApp.showMessage(this.$t('Observation saved!')); + this.vnApp.showSuccess(this.$t('Observation saved!')); + this.sendMail(); this.$state.reload(); }); } + sendMail() { + const params = { + defaulters: this.checked, + observation: this.defaulter.observation + }; + this.$http.post(`Defaulters/observationEmail`, params); + } + exprBuilder(param, value) { switch (param) { case 'creditInsurance': @@ -122,8 +145,25 @@ export default class Controller extends Section { case 'workerFk': case 'salesPersonFk': return {[`d.${param}`]: value}; + case 'created': + return {'d.created': { + between: this.dateRange(value)} + }; + case 'defaulterSinced': + return {'d.defaulterSinced': { + between: this.dateRange(value)} + }; } } + + dateRange(value) { + const minHour = new Date(value); + minHour.setHours(0, 0, 0, 0); + const maxHour = new Date(value); + maxHour.setHours(23, 59, 59, 59); + + return [minHour, maxHour]; + } } ngModule.vnComponent('vnClientDefaulter', { diff --git a/modules/client/front/defaulter/index.spec.js b/modules/client/front/defaulter/index.spec.js index f92378d08..b4a9df184 100644 --- a/modules/client/front/defaulter/index.spec.js +++ b/modules/client/front/defaulter/index.spec.js @@ -81,14 +81,15 @@ describe('client defaulter', () => { const params = [{text: controller.defaulter.observation, clientFk: data[1].clientFk}]; - jest.spyOn(controller.vnApp, 'showMessage'); + jest.spyOn(controller.vnApp, 'showSuccess'); $httpBackend.expect('GET', `Defaulters/filter`).respond(200); $httpBackend.expect('POST', `ClientObservations`, params).respond(200, params); + $httpBackend.expect('POST', `Defaulters/observationEmail`).respond(200); controller.onResponse(); $httpBackend.flush(); - expect(controller.vnApp.showMessage).toHaveBeenCalledWith('Observation saved!'); + expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Observation saved!'); }); }); @@ -117,5 +118,62 @@ describe('client defaulter', () => { expect(controller.balanceDueTotal).toEqual(875); }); }); + + describe('dateRange()', () => { + it('should return two dates with the hours at the start and end of the given date', () => { + const now = Date.vnNew(); + + const today = now.getDate(); + + const dateRange = controller.dateRange(now); + const start = dateRange[0].toString(); + const end = dateRange[1].toString(); + + expect(start).toContain(today); + expect(start).toContain('00:00:00'); + + expect(end).toContain(today); + expect(end).toContain('23:59:59'); + }); + }); + + describe('reCheck()', () => { + it(`should recheck buys`, () => { + controller.$.model.data = [ + {checked: false, clientFk: 1}, + {checked: false, clientFk: 2}, + {checked: false, clientFk: 3}, + {checked: false, clientFk: 4}, + ]; + controller.checkedDefaulers = [1, 2]; + + controller.reCheck(); + + expect(controller.$.model.data[0].checked).toEqual(true); + expect(controller.$.model.data[1].checked).toEqual(true); + expect(controller.$.model.data[2].checked).toEqual(false); + expect(controller.$.model.data[3].checked).toEqual(false); + }); + }); + + describe('saveChecked()', () => { + it(`should check buy`, () => { + const buyCheck = 3; + controller.checkedDefaulers = [1, 2]; + + controller.saveChecked(buyCheck); + + expect(controller.checkedDefaulers[2]).toEqual(buyCheck); + }); + + it(`should uncheck buy`, () => { + const buyUncheck = 3; + controller.checkedDefaulers = [1, 2, 3]; + + controller.saveChecked(buyUncheck); + + expect(controller.checkedDefaulers[2]).toEqual(undefined); + }); + }); }); }); diff --git a/modules/client/front/defaulter/locale/es.yml b/modules/client/front/defaulter/locale/es.yml index c3e1d4e19..fe06a15a1 100644 --- a/modules/client/front/defaulter/locale/es.yml +++ b/modules/client/front/defaulter/locale/es.yml @@ -6,4 +6,6 @@ Last observation: Última observación L. O. Date: Fecha Ú. O. Last observation date: Fecha última observación Search client: Buscar clientes -Worker who made the last observation: Trabajador que ha realizado la última observación \ No newline at end of file +Worker who made the last observation: Trabajador que ha realizado la última observación +Email sended!: Email enviado! +Observation saved!: Observación añadida! diff --git a/modules/client/front/descriptor/index.html b/modules/client/front/descriptor/index.html index edf3cc8c3..5aaecbdb0 100644 --- a/modules/client/front/descriptor/index.html +++ b/modules/client/front/descriptor/index.html @@ -70,11 +70,12 @@ icon="icon-no036" ng-if="$ctrl.client.isTaxDataChecked == false"> - - +
diff --git a/modules/client/front/unpaid/index.js b/modules/client/front/unpaid/index.js index fcf620b54..1585b808d 100644 --- a/modules/client/front/unpaid/index.js +++ b/modules/client/front/unpaid/index.js @@ -6,9 +6,17 @@ export default class Controller extends Section { if (hasData && !this.clientUnpaid.dated) this.clientUnpaid.dated = Date.vnNew(); } + + onSubmit() { + this.$.watcher.submit() + .then(() => this.card.reload()); + } } ngModule.vnComponent('vnClientUnpaid', { template: require('./index.html'), - controller: Controller + controller: Controller, + require: { + card: '^vnClientCard' + } }); diff --git a/modules/client/front/web-payment/index.html b/modules/client/front/web-payment/index.html index 203d4bb60..2ecfc950b 100644 --- a/modules/client/front/web-payment/index.html +++ b/modules/client/front/web-payment/index.html @@ -1,55 +1,39 @@ - + - + - - - - State - Id - Date - Amount - - - - - - - - - - - - {{::transaction.id}} - {{::transaction.created | date:'dd/MM/yyyy HH:mm'}} - {{::transaction.amount | currency: 'EUR':2}} - - - - - - - + + + + State + Id + Date + Amount + + + + + + + + + + + + {{::transaction.id}} + {{::transaction.created | date:'dd/MM/yyyy HH:mm'}} + {{::transaction.amount | currency: 'EUR':2}} + + + + + + + \ No newline at end of file diff --git a/modules/entry/back/methods/entry/entryOrderPdf.js b/modules/entry/back/methods/entry/entryOrderPdf.js index e6d37fdb6..f77832162 100644 --- a/modules/entry/back/methods/entry/entryOrderPdf.js +++ b/modules/entry/back/methods/entry/entryOrderPdf.js @@ -1,5 +1,3 @@ -const {Report} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('entryOrderPdf', { description: 'Returns the entry order pdf', @@ -38,17 +36,5 @@ module.exports = Self => { } }); - Self.entryOrderPdf = 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('entry-order', params); - const stream = await report.toPdfStream(); - - return [stream, 'application/pdf', `filename="doc-${id}.pdf"`]; - }; + Self.entryOrderPdf = (ctx, id) => Self.printReport(ctx, id, 'entry-order'); }; diff --git a/modules/entry/back/methods/entry/specs/editLatestBuys.spec.js b/modules/entry/back/methods/entry/specs/editLatestBuys.spec.js index 86ed9dddc..99d2df67b 100644 --- a/modules/entry/back/methods/entry/specs/editLatestBuys.spec.js +++ b/modules/entry/back/methods/entry/specs/editLatestBuys.spec.js @@ -1,6 +1,22 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('Buy editLatestsBuys()', () => { + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); + it('should change the value of a given column for the selected buys', async() => { const tx = await models.Buy.beginTransaction({}); const options = {transaction: tx}; diff --git a/modules/entry/back/models/buy.json b/modules/entry/back/models/buy.json index 8e36d0eef..379e55427 100644 --- a/modules/entry/back/models/buy.json +++ b/modules/entry/back/models/buy.json @@ -1,10 +1,6 @@ { "name": "Buy", "base": "Loggable", - "log": { - "model": "EntryLog", - "relation": "entry" - }, "options": { "mysql": { "table": "buy" @@ -70,4 +66,4 @@ "foreignKey": "packageFk" } } -} \ No newline at end of file +} diff --git a/modules/entry/back/models/entry-observation.json b/modules/entry/back/models/entry-observation.json index 0c63dd663..cdf0c5e6e 100644 --- a/modules/entry/back/models/entry-observation.json +++ b/modules/entry/back/models/entry-observation.json @@ -1,10 +1,6 @@ { "name": "EntryObservation", "base": "Loggable", - "log": { - "model": "EntryLog", - "relation": "entry" - }, "options": { "mysql": { "table": "entryObservation" diff --git a/modules/entry/back/models/entry.json b/modules/entry/back/models/entry.json index 6c5e1b7d3..3933f6a34 100644 --- a/modules/entry/back/models/entry.json +++ b/modules/entry/back/models/entry.json @@ -1,9 +1,6 @@ { "name": "Entry", "base": "Loggable", - "log": { - "model":"EntryLog" - }, "options": { "mysql": { "table": "entry" diff --git a/modules/invoiceIn/back/methods/invoice-in/getSerial.js b/modules/invoiceIn/back/methods/invoice-in/getSerial.js new file mode 100644 index 000000000..dcc1fbc3c --- /dev/null +++ b/modules/invoiceIn/back/methods/invoice-in/getSerial.js @@ -0,0 +1,65 @@ +const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; +const buildFilter = require('vn-loopback/util/filter').buildFilter; +const mergeFilters = require('vn-loopback/util/filter').mergeFilters; + +module.exports = Self => { + Self.remoteMethodCtx('getSerial', { + description: 'Return invoiceIn serial', + accessType: 'READ', + accepts: [{ + arg: 'filter', + type: 'object' + }, { + arg: 'daysAgo', + type: 'number', + required: true + }, { + arg: 'serial', + type: 'string' + }], + returns: { + type: 'object', + root: true + }, + http: { + path: '/getSerial', + verb: 'GET' + } + }); + + Self.getSerial = async(ctx, options) => { + const conn = Self.dataSource.connector; + const args = ctx.args; + const myOptions = {}; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + const issued = Date.vnNew(); + const where = buildFilter(args, (param, value) => { + switch (param) { + case 'daysAgo': + issued.setDate(issued.getDate() - value); + return {'i.issued': {gte: issued}}; + case 'serial': + return {'i.serial': {like: `%${value}%`}}; + } + }); + + filter = mergeFilters(args.filter, {where}); + + const stmt = new ParameterizedSQL( + `SELECT i.serial, SUM(IF(i.isBooked, 0,1)) pending, COUNT(*) total + FROM vn.invoiceIn i` + ); + + stmt.merge(conn.makeWhere(filter.where)); + stmt.merge(`GROUP BY i.serial`); + stmt.merge(conn.makeOrderBy(filter.order)); + stmt.merge(conn.makeLimit(filter)); + + const result = await conn.executeStmt(stmt, myOptions); + + return result; + }; +}; diff --git a/modules/invoiceIn/back/methods/invoice-in/invoiceInEmail.js b/modules/invoiceIn/back/methods/invoice-in/invoiceInEmail.js index 0768541a8..a0af3da69 100644 --- a/modules/invoiceIn/back/methods/invoice-in/invoiceInEmail.js +++ b/modules/invoiceIn/back/methods/invoice-in/invoiceInEmail.js @@ -1,5 +1,3 @@ -const {Email} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('invoiceInEmail', { description: 'Sends the invoice in email with an attached PDF', @@ -35,19 +33,5 @@ module.exports = Self => { } }); - Self.invoiceInEmail = async ctx => { - 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('invoiceIn', params); - - return email.send(); - }; + Self.invoiceInEmail = ctx => Self.sendTemplate(ctx, 'invoiceIn'); }; diff --git a/modules/invoiceIn/back/methods/invoice-in/invoiceInPdf.js b/modules/invoiceIn/back/methods/invoice-in/invoiceInPdf.js index e7962c93f..681a19fc6 100644 --- a/modules/invoiceIn/back/methods/invoice-in/invoiceInPdf.js +++ b/modules/invoiceIn/back/methods/invoice-in/invoiceInPdf.js @@ -1,5 +1,3 @@ -const {Report} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('invoiceInPdf', { description: 'Returns the invoiceIn pdf', @@ -34,17 +32,5 @@ module.exports = Self => { } }); - Self.invoiceInPdf = 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('invoiceIn', params); - const stream = await report.toPdfStream(); - - return [stream, 'application/pdf', `filename="doc-${id}.pdf"`]; - }; + Self.invoiceInPdf = (ctx, id) => Self.printReport(ctx, id, 'invoiceIn'); }; diff --git a/modules/invoiceIn/back/methods/invoice-in/negativeBases.js b/modules/invoiceIn/back/methods/invoice-in/negativeBases.js new file mode 100644 index 000000000..4d5975fab --- /dev/null +++ b/modules/invoiceIn/back/methods/invoice-in/negativeBases.js @@ -0,0 +1,112 @@ +const UserError = require('vn-loopback/util/user-error'); +const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; + +module.exports = Self => { + Self.remoteMethodCtx('negativeBases', { + description: 'Find all negative bases', + accessType: 'READ', + accepts: [ + { + arg: 'from', + type: 'date', + description: 'From date' + }, + { + arg: 'to', + type: 'date', + description: 'To date' + }, + { + arg: 'filter', + type: 'object', + description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string' + }, + ], + returns: { + type: ['object'], + root: true + }, + http: { + path: `/negativeBases`, + verb: 'GET' + } + }); + + Self.negativeBases = async(ctx, options) => { + const conn = Self.dataSource.connector; + const args = ctx.args; + + if (!args.from || !args.to) + throw new UserError(`Insert a date range`); + + const myOptions = {}; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + const stmts = []; + let stmt; + stmts.push(`DROP TEMPORARY TABLE IF EXISTS tmp.ticket`); + + stmts.push(new ParameterizedSQL( + `CREATE TEMPORARY TABLE tmp.ticket + (KEY (ticketFk)) + ENGINE = MEMORY + SELECT id ticketFk + FROM ticket t + WHERE shipped BETWEEN ? AND ? + AND refFk IS NULL`, [args.from, args.to])); + stmts.push(`CALL vn.ticket_getTax(NULL)`); + stmts.push(`DROP TEMPORARY TABLE IF EXISTS tmp.filter`); + stmts.push(new ParameterizedSQL( + `CREATE TEMPORARY TABLE tmp.filter + ENGINE = MEMORY + SELECT + co.code company, + cou.country, + c.id clientId, + c.socialName clientSocialName, + SUM(s.quantity * s.price * ( 100 - s.discount ) / 100) amount, + negativeBase.taxableBase, + negativeBase.ticketFk, + c.isActive, + c.hasToInvoice, + c.isTaxDataChecked, + w.id comercialId, + CONCAT(w.firstName, ' ', w.lastName) comercialName + FROM vn.ticket t + JOIN vn.company co ON co.id = t.companyFk + JOIN vn.sale s ON s.ticketFk = t.id + JOIN vn.client c ON c.id = t.clientFk + JOIN vn.country cou ON cou.id = c.countryFk + LEFT JOIN vn.worker w ON w.id = c.salesPersonFk + LEFT JOIN ( + SELECT ticketFk, taxableBase + FROM tmp.ticketAmount + GROUP BY ticketFk + HAVING taxableBase < 0 + ) negativeBase ON negativeBase.ticketFk = t.id + WHERE t.shipped BETWEEN ? AND ? + AND t.refFk IS NULL + AND c.typeFk IN ('normal','trust') + GROUP BY t.clientFk, negativeBase.taxableBase + HAVING amount <> 0`, [args.from, args.to])); + + stmt = new ParameterizedSQL(` + SELECT f.* + FROM tmp.filter f`); + + stmt.merge(conn.makeWhere(args.filter.where)); + stmt.merge(conn.makeOrderBy(args.filter.order)); + + const negativeBasesIndex = stmts.push(stmt) - 1; + + stmts.push(`DROP TEMPORARY TABLE tmp.filter, tmp.ticket, tmp.ticketTax, tmp.ticketAmount`); + + const sql = ParameterizedSQL.join(stmts, ';'); + const result = await conn.executeStmt(sql, myOptions); + + return negativeBasesIndex === 0 ? result : result[negativeBasesIndex]; + }; +}; + diff --git a/modules/invoiceIn/back/methods/invoice-in/negativeBasesCsv.js b/modules/invoiceIn/back/methods/invoice-in/negativeBasesCsv.js new file mode 100644 index 000000000..963151b7d --- /dev/null +++ b/modules/invoiceIn/back/methods/invoice-in/negativeBasesCsv.js @@ -0,0 +1,53 @@ +const {toCSV} = require('vn-loopback/util/csv'); + +module.exports = Self => { + Self.remoteMethodCtx('negativeBasesCsv', { + description: 'Returns the negative bases as .csv', + accessType: 'READ', + accepts: [{ + arg: 'negativeBases', + type: ['object'], + required: true + }, + { + arg: 'from', + type: 'date', + description: 'From date' + }, + { + arg: 'to', + type: 'date', + description: 'To date' + }], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'String', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'String', + http: {target: 'header'} + } + ], + http: { + path: '/negativeBasesCsv', + verb: 'GET' + } + }); + + Self.negativeBasesCsv = async ctx => { + const args = ctx.args; + const content = toCSV(args.negativeBases); + + return [ + content, + 'text/csv', + `attachment; filename="negative-bases-${new Date(args.from).toLocaleDateString()}-${new Date(args.to).toLocaleDateString()}.csv"` + ]; + }; +}; diff --git a/modules/invoiceIn/back/methods/invoice-in/specs/clone.spec.js b/modules/invoiceIn/back/methods/invoice-in/specs/clone.spec.js index e0f191962..42ebe52b3 100644 --- a/modules/invoiceIn/back/methods/invoice-in/specs/clone.spec.js +++ b/modules/invoiceIn/back/methods/invoice-in/specs/clone.spec.js @@ -1,6 +1,21 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('invoiceIn clone()', () => { + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); + it('should return the cloned invoiceIn and also clone invoiceInDueDays and invoiceInTaxes if there are any referencing the invoiceIn', async() => { const userId = 1; const ctx = { diff --git a/modules/invoiceIn/back/methods/invoice-in/specs/getSerial.spec.js b/modules/invoiceIn/back/methods/invoice-in/specs/getSerial.spec.js new file mode 100644 index 000000000..6224ce9ac --- /dev/null +++ b/modules/invoiceIn/back/methods/invoice-in/specs/getSerial.spec.js @@ -0,0 +1,24 @@ +const models = require('vn-loopback/server/server').models; + +describe('invoiceIn getSerial()', () => { + it('should check that returns without serial param', async() => { + const ctx = {args: {daysAgo: 45}}; + const result = await models.InvoiceIn.getSerial(ctx); + + expect(result.length).toBeGreaterThan(0); + }); + + it('should check that returns with serial param', async() => { + const ctx = {args: {daysAgo: 45, serial: 'R'}}; + const result = await models.InvoiceIn.getSerial(ctx); + + expect(result.length).toBeGreaterThan(0); + }); + + it('should check that returns with non exist serial param', async() => { + const ctx = {args: {daysAgo: 45, serial: 'Mock serial'}}; + const result = await models.InvoiceIn.getSerial(ctx); + + expect(result.length).toEqual(0); + }); +}); diff --git a/modules/invoiceIn/back/methods/invoice-in/specs/negativeBases.spec.js b/modules/invoiceIn/back/methods/invoice-in/specs/negativeBases.spec.js new file mode 100644 index 000000000..a5c6e3102 --- /dev/null +++ b/modules/invoiceIn/back/methods/invoice-in/specs/negativeBases.spec.js @@ -0,0 +1,47 @@ +const models = require('vn-loopback/server/server').models; + +describe('invoiceIn negativeBases()', () => { + it('should return all negative bases in a date range', async() => { + const tx = await models.InvoiceIn.beginTransaction({}); + const options = {transaction: tx}; + const ctx = { + args: { + from: new Date().setMonth(new Date().getMonth() - 12), + to: new Date(), + filter: {} + } + }; + + try { + const result = await models.InvoiceIn.negativeBases(ctx, options); + + expect(result.length).toBeGreaterThan(0); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + + it('should throw an error if a date range is not in args', async() => { + let error; + const tx = await models.InvoiceIn.beginTransaction({}); + const options = {transaction: tx}; + const ctx = { + args: { + filter: {} + } + }; + + try { + await models.InvoiceIn.negativeBases(ctx, options); + await tx.rollback(); + } catch (e) { + error = e; + await tx.rollback(); + } + + expect(error.message).toEqual(`Insert a date range`); + }); +}); diff --git a/modules/invoiceIn/back/models/invoice-in-config.json b/modules/invoiceIn/back/models/invoice-in-config.json index 5cf0ed64c..c0236e654 100644 --- a/modules/invoiceIn/back/models/invoice-in-config.json +++ b/modules/invoiceIn/back/models/invoice-in-config.json @@ -17,6 +17,9 @@ }, "retentionName": { "type": "string" + }, + "daysAgo": { + "type": "number" } }, "relations": { diff --git a/modules/invoiceIn/back/models/invoice-in-tax.json b/modules/invoiceIn/back/models/invoice-in-tax.json index 789020161..1f68476c3 100644 --- a/modules/invoiceIn/back/models/invoice-in-tax.json +++ b/modules/invoiceIn/back/models/invoice-in-tax.json @@ -1,10 +1,6 @@ { "name": "InvoiceInTax", "base": "Loggable", - "log": { - "model": "InvoiceInLog", - "relation": "invoiceIn" - }, "options": { "mysql": { "table": "invoiceInTax" @@ -55,4 +51,4 @@ "foreignKey": "transactionTypeSageFk" } } -} \ No newline at end of file +} diff --git a/modules/invoiceIn/back/models/invoice-in.js b/modules/invoiceIn/back/models/invoice-in.js index 95ccc7b20..167f2ac34 100644 --- a/modules/invoiceIn/back/models/invoice-in.js +++ b/modules/invoiceIn/back/models/invoice-in.js @@ -6,4 +6,7 @@ module.exports = Self => { require('../methods/invoice-in/getTotals')(Self); require('../methods/invoice-in/invoiceInPdf')(Self); require('../methods/invoice-in/invoiceInEmail')(Self); + require('../methods/invoice-in/getSerial')(Self); + require('../methods/invoice-in/negativeBases')(Self); + require('../methods/invoice-in/negativeBasesCsv')(Self); }; diff --git a/modules/invoiceIn/back/models/invoice-in.json b/modules/invoiceIn/back/models/invoice-in.json index c6a736b06..754899866 100644 --- a/modules/invoiceIn/back/models/invoice-in.json +++ b/modules/invoiceIn/back/models/invoice-in.json @@ -1,9 +1,6 @@ { "name": "InvoiceIn", "base": "Loggable", - "log": { - "model": "InvoiceInLog" - }, "options": { "mysql": { "table": "invoiceIn" diff --git a/modules/invoiceIn/front/index.js b/modules/invoiceIn/front/index.js index 7b6d6a77c..c0374e996 100644 --- a/modules/invoiceIn/front/index.js +++ b/modules/invoiceIn/front/index.js @@ -13,3 +13,6 @@ import './dueDay'; import './intrastat'; import './create'; import './log'; +import './serial'; +import './serial-search-panel'; +import './negative-bases'; diff --git a/modules/invoiceIn/front/locale/es.yml b/modules/invoiceIn/front/locale/es.yml index 35b43f9f6..017e89dd4 100644 --- a/modules/invoiceIn/front/locale/es.yml +++ b/modules/invoiceIn/front/locale/es.yml @@ -7,6 +7,7 @@ Foreign value: Divisa InvoiceIn: Facturas recibidas InvoiceIn cloned: Factura clonada InvoiceIn deleted: Factura eliminada +InvoiceIn Serial: Facturas por series Invoice list: Listado de facturas recibidas InvoiceIn booked: Factura contabilizada Net: Neto @@ -22,3 +23,5 @@ Total stems: Total tallos Show agricultural receipt as PDF: Ver recibo agrícola como PDF Send agricultural receipt as PDF: Enviar recibo agrícola como PDF New InvoiceIn: Nueva Factura +Days ago: Últimos días +Negative bases: Bases negativas diff --git a/modules/invoiceIn/front/negative-bases/index.html b/modules/invoiceIn/front/negative-bases/index.html new file mode 100644 index 000000000..368f44461 --- /dev/null +++ b/modules/invoiceIn/front/negative-bases/index.html @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Company + + Country + + Id Client + + Client + + Amount + + Base + + Id Ticket + + Active + + Has To Invoice + + Verified data + + Comercial +
{{client.company | dashIfEmpty}}{{client.country | dashIfEmpty}} + + {{::client.clientId | dashIfEmpty}} + + {{client.clientSocialName | dashIfEmpty}}{{client.amount | currency: 'EUR':2 | dashIfEmpty}}{{client.taxableBase | dashIfEmpty}} + + {{::client.ticketFk | dashIfEmpty}} + + + + + + + + + + + + + {{::client.comercialName | dashIfEmpty}} + +
+
+
+
+ + + + + + diff --git a/modules/invoiceIn/front/negative-bases/index.js b/modules/invoiceIn/front/negative-bases/index.js new file mode 100644 index 000000000..0f6f04692 --- /dev/null +++ b/modules/invoiceIn/front/negative-bases/index.js @@ -0,0 +1,84 @@ +import ngModule from '../module'; +import Section from 'salix/components/section'; +import './style.scss'; + +export default class Controller extends Section { + constructor($element, $, vnReport) { + super($element, $); + + this.vnReport = vnReport; + const now = new Date(); + const firstDayOfMonth = new Date(now.getFullYear(), now.getMonth(), 1); + const lastDayOfMonth = new Date(now.getFullYear(), now.getMonth() + 1, 0); + this.params = { + from: firstDayOfMonth, + to: lastDayOfMonth + }; + this.$checkAll = false; + + this.smartTableOptions = { + activeButtons: { + search: true, + }, columns: [ + { + field: 'isActive', + searchable: false + }, + { + field: 'hasToInvoice', + searchable: false + }, + { + field: 'isTaxDataChecked', + searchable: false + }, + ] + }; + } + + exprBuilder(param, value) { + switch (param) { + case 'company': + return {'company': value}; + case 'country': + return {'country': value}; + case 'clientId': + return {'clientId': value}; + case 'clientSocialName': + return {'clientSocialName': value}; + case 'amount': + return {'amount': value}; + case 'taxableBase': + return {'taxableBase': value}; + case 'ticketFk': + return {'ticketFk': value}; + case 'comercialName': + return {'comercialName': value}; + } + } + + downloadCSV() { + const data = []; + this.$.model._orgData.forEach(element => { + data.push(Object.keys(element).map(key => { + return {newName: this.$t(key), value: element[key]}; + }).filter(item => item !== null) + .reduce((result, item) => { + result[item.newName] = item.value; + return result; + }, {})); + }); + this.vnReport.show('InvoiceIns/negativeBasesCsv', { + negativeBases: data, + from: this.params.from, + to: this.params.to + }); + } +} + +Controller.$inject = ['$element', '$scope', 'vnReport']; + +ngModule.vnComponent('vnNegativeBases', { + template: require('./index.html'), + controller: Controller +}); diff --git a/modules/invoiceIn/front/negative-bases/locale/es.yml b/modules/invoiceIn/front/negative-bases/locale/es.yml new file mode 100644 index 000000000..9095eee22 --- /dev/null +++ b/modules/invoiceIn/front/negative-bases/locale/es.yml @@ -0,0 +1,14 @@ +Has To Invoice: Facturar +Download as CSV: Descargar como CSV +company: Compañía +country: País +clientId: Id Cliente +clientSocialName: Cliente +amount: Importe +taxableBase: Base +ticketFk: Id Ticket +isActive: Activo +hasToInvoice: Facturar +isTaxDataChecked: Datos comprobados +comercialId: Id Comercial +comercialName: Comercial diff --git a/modules/invoiceIn/front/negative-bases/style.scss b/modules/invoiceIn/front/negative-bases/style.scss new file mode 100644 index 000000000..2d628cb94 --- /dev/null +++ b/modules/invoiceIn/front/negative-bases/style.scss @@ -0,0 +1,10 @@ +@import "./variables"; + +vn-negative-bases { + vn-date-picker{ + padding-right: 5%; + } + slot-actions{ + align-items: center; + } +} diff --git a/modules/invoiceIn/front/routes.json b/modules/invoiceIn/front/routes.json index 4867b7db9..40d061d1b 100644 --- a/modules/invoiceIn/front/routes.json +++ b/modules/invoiceIn/front/routes.json @@ -9,10 +9,9 @@ ], "menus": { "main": [ - { - "state": "invoiceIn.index", - "icon": "icon-invoice-in" - } + { "state": "invoiceIn.index", "icon": "icon-invoice-in"}, + { "state": "invoiceIn.serial", "icon": "icon-invoice-in"}, + { "state": "invoiceIn.negative-bases", "icon": "icon-ticket"} ], "card": [ { @@ -54,6 +53,24 @@ "administrative" ] }, + { + "url": "/negative-bases", + "state": "invoiceIn.negative-bases", + "component": "vn-negative-bases", + "description": "Negative bases", + "acl": [ + "administrative" + ] + }, + { + "url": "/serial", + "state": "invoiceIn.serial", + "component": "vn-invoice-in-serial", + "description": "InvoiceIn Serial", + "acl": [ + "administrative" + ] + }, { "url": "/:id", "state": "invoiceIn.card", @@ -133,4 +150,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/modules/invoiceIn/front/serial-search-panel/index.html b/modules/invoiceIn/front/serial-search-panel/index.html new file mode 100644 index 000000000..0dda54852 --- /dev/null +++ b/modules/invoiceIn/front/serial-search-panel/index.html @@ -0,0 +1,27 @@ + + + + + + + + + +
+ + {{$ctrl.$t('Serial')}}: {{$ctrl.filter.serial}} + +
+
diff --git a/modules/invoiceIn/front/serial-search-panel/index.js b/modules/invoiceIn/front/serial-search-panel/index.js new file mode 100644 index 000000000..b11911ee3 --- /dev/null +++ b/modules/invoiceIn/front/serial-search-panel/index.js @@ -0,0 +1,44 @@ +import ngModule from '../module'; +import SearchPanel from 'core/components/searchbar/search-panel'; +import './style.scss'; + +class Controller extends SearchPanel { + constructor($element, $) { + super($element, $); + this.filter = {}; + const filter = { + fields: ['daysAgo'] + }; + this.$http.get('InvoiceInConfigs', {filter}).then(res => { + if (res.data) { + this.invoiceInConfig = res.data[0]; + this.addFilters(); + } + }); + } + + removeItemFilter(param) { + this.filter[param] = null; + this.addFilters(); + } + + onKeyPress($event) { + if ($event.key === 'Enter') + this.addFilters(); + } + + addFilters() { + if (!this.filter.daysAgo) + this.filter.daysAgo = this.invoiceInConfig.daysAgo; + + return this.model.addFilter({}, this.filter); + } +} + +ngModule.component('vnInvoiceInSerialSearchPanel', { + template: require('./index.html'), + controller: Controller, + bindings: { + model: '<' + } +}); diff --git a/modules/invoiceIn/front/serial-search-panel/index.spec.js b/modules/invoiceIn/front/serial-search-panel/index.spec.js new file mode 100644 index 000000000..b5228e126 --- /dev/null +++ b/modules/invoiceIn/front/serial-search-panel/index.spec.js @@ -0,0 +1,43 @@ +import './index.js'; + +describe('InvoiceIn', () => { + describe('Component serial-search-panel', () => { + let controller; + let $scope; + + beforeEach(ngModule('invoiceIn')); + + beforeEach(inject(($componentController, $rootScope) => { + $scope = $rootScope.$new(); + const $element = angular.element(''); + controller = $componentController('vnInvoiceInSerialSearchPanel', {$element, $scope}); + controller.model = { + addFilter: jest.fn(), + }; + controller.invoiceInConfig = { + daysAgo: 45, + }; + })); + + describe('addFilters()', () => { + it('should add default daysAgo if it is not already set', () => { + controller.filter = { + serial: 'R', + }; + controller.addFilters(); + + expect(controller.filter.daysAgo).toEqual(controller.invoiceInConfig.daysAgo); + }); + + it('should not add default daysAgo if it is already set', () => { + controller.filter = { + daysAgo: 1, + serial: 'R', + }; + controller.addFilters(); + + expect(controller.filter.daysAgo).toEqual(1); + }); + }); + }); +}); diff --git a/modules/invoiceIn/front/serial-search-panel/style.scss b/modules/invoiceIn/front/serial-search-panel/style.scss new file mode 100644 index 000000000..4abfcbfa2 --- /dev/null +++ b/modules/invoiceIn/front/serial-search-panel/style.scss @@ -0,0 +1,24 @@ +@import "variables"; + +vn-invoice-in-serial-search-panel vn-side-menu div { + & > .input { + padding-left: $spacing-md; + padding-right: $spacing-md; + border-color: $color-spacer; + border-bottom: $border-thin; + } + & > .horizontal { + grid-auto-flow: column; + grid-column-gap: $spacing-sm; + align-items: center; + } + & > .chips { + display: flex; + flex-wrap: wrap; + padding: $spacing-md; + overflow: hidden; + max-width: 100%; + border-color: $color-spacer; + border-top: $border-thin; + } +} diff --git a/modules/invoiceIn/front/serial/index.html b/modules/invoiceIn/front/serial/index.html new file mode 100644 index 000000000..1649ec7d7 --- /dev/null +++ b/modules/invoiceIn/front/serial/index.html @@ -0,0 +1,40 @@ + + + + + + + + + + + + Serial + Pending + Total + + + + + + {{::invoiceIn.serial}} + {{::invoiceIn.pending}} + {{::invoiceIn.total}} + + + + + + + + + diff --git a/modules/invoiceIn/front/serial/index.js b/modules/invoiceIn/front/serial/index.js new file mode 100644 index 000000000..193a57492 --- /dev/null +++ b/modules/invoiceIn/front/serial/index.js @@ -0,0 +1,22 @@ +import ngModule from '../module'; +import Section from 'salix/components/section'; + +export default class Controller extends Section { + constructor($element, $) { + super($element, $); + } + + goToIndex(daysAgo, serial) { + const issued = Date.vnNew(); + issued.setDate(issued.getDate() - daysAgo); + this.$state.go('invoiceIn.index', + {q: `{"serial": "${serial}", "isBooked": false, "from": ${issued.getTime()}}`}); + } +} + +Controller.$inject = ['$element', '$scope']; + +ngModule.vnComponent('vnInvoiceInSerial', { + template: require('./index.html'), + controller: Controller +}); diff --git a/modules/invoiceIn/front/serial/locale/es.yml b/modules/invoiceIn/front/serial/locale/es.yml new file mode 100644 index 000000000..92a49cc82 --- /dev/null +++ b/modules/invoiceIn/front/serial/locale/es.yml @@ -0,0 +1,3 @@ +Serial: Serie +Pending: Pendientes +Go to InvoiceIn: Ir al listado de facturas recibidas diff --git a/modules/invoiceOut/back/methods/invoiceOut/clientsToInvoice.js b/modules/invoiceOut/back/methods/invoiceOut/clientsToInvoice.js index f3c7a5093..f18b0c682 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/clientsToInvoice.js +++ b/modules/invoiceOut/back/methods/invoiceOut/clientsToInvoice.js @@ -4,47 +4,37 @@ module.exports = Self => { accessType: 'WRITE', accepts: [ { + arg: 'clientId', + type: 'number', + description: 'The client id' + }, { arg: 'invoiceDate', type: 'date', - description: 'The invoice date' - }, - { + description: 'The invoice date', + required: true + }, { arg: 'maxShipped', type: 'date', - description: 'The maximum shipped date' - }, - { - arg: 'fromClientId', - type: 'number', - description: 'The minimum client id' - }, - { - arg: 'toClientId', - type: 'number', - description: 'The maximum client id' - }, - { + description: 'The maximum shipped date', + required: true + }, { arg: 'companyFk', type: 'number', - description: 'The company id to invoice' - } + description: 'The company id to invoice', + required: true + }, ], - returns: [{ - arg: 'clientsAndAddresses', - type: ['object'] + returns: { + type: 'Object', + root: true }, - { - arg: 'invoice', - type: 'object' - }], http: { path: '/clientsToInvoice', verb: 'POST' } }); - Self.clientsToInvoice = async(ctx, options) => { - const args = ctx.args; + Self.clientsToInvoice = async(ctx, clientId, invoiceDate, maxShipped, companyFk, options) => { let tx; const myOptions = {}; @@ -56,134 +46,52 @@ module.exports = Self => { myOptions.transaction = tx; } - let query; try { - query = ` - SELECT MAX(issued) issued - FROM vn.invoiceOut io - JOIN vn.time t ON t.dated = io.issued - WHERE io.serial = 'A' - AND t.year = YEAR(?) - AND io.companyFk = ?`; - const [maxIssued] = await Self.rawSql(query, [ - args.invoiceDate, - args.companyFk - ], myOptions); - - const maxSerialDate = maxIssued.issued || args.invoiceDate; - if (args.invoiceDate < maxSerialDate) - args.invoiceDate = maxSerialDate; - - if (args.invoiceDate < args.maxShipped) - args.maxShipped = args.invoiceDate; - - const minShipped = Date.vnNew(); - minShipped.setFullYear(minShipped.getFullYear() - 1); - minShipped.setMonth(1); - minShipped.setDate(1); - minShipped.setHours(0, 0, 0, 0); - // Packaging liquidation const vIsAllInvoiceable = false; - const clientsWithPackaging = await getClientsWithPackaging(ctx, myOptions); - for (let client of clientsWithPackaging) { - await Self.rawSql('CALL packageInvoicing(?, ?, ?, ?, @newTicket)', [ - client.id, - args.invoiceDate, - args.companyFk, - vIsAllInvoiceable - ], myOptions); - } + await Self.rawSql('CALL ticketPackaging_add(?, ?, ?, ?)', [ + clientId, + invoiceDate, + companyFk, + vIsAllInvoiceable + ], myOptions); - const invoiceableClients = await getInvoiceableClients(ctx, myOptions); + const minShipped = Date.vnNew(); + minShipped.setFullYear(maxShipped.getFullYear() - 1); - if (!invoiceableClients) return; + const query = ` + SELECT c.id clientId, + c.name clientName, + a.id, + a.nickname + FROM ticket t + JOIN address a ON a.id = t.addressFk + JOIN client c ON c.id = t.clientFk + WHERE t.refFk IS NULL + AND t.shipped BETWEEN ? AND util.dayEnd(?) + AND (t.clientFk = ? OR ? IS NULL ) + AND t.companyFk = ? + AND c.hasToInvoice + AND c.isTaxDataChecked + AND c.isActive + AND NOT t.isDeleted + GROUP BY c.id, IF(c.hasToInvoiceByAddress, a.id, TRUE) + HAVING SUM(t.totalWithVat) > 0;`; - const clientsAndAddresses = invoiceableClients.map(invoiceableClient => { - return { - clientId: invoiceableClient.id, - addressId: invoiceableClient.addressFk - - }; - } - ); + const addresses = await Self.rawSql(query, [ + minShipped, + maxShipped, + clientId, + clientId, + companyFk + ], myOptions); if (tx) await tx.commit(); - return [ - clientsAndAddresses, - { - invoiceDate: args.invoiceDate, - maxShipped: args.maxShipped, - fromClientId: args.fromClientId, - toClientId: args.toClientId, - companyFk: args.companyFk, - minShipped: minShipped - } - ]; + return addresses; } catch (e) { if (tx) await tx.rollback(); throw e; } }; - - async function getClientsWithPackaging(ctx, options) { - const models = Self.app.models; - const args = ctx.args; - const query = `SELECT DISTINCT clientFk AS id - FROM ticket t - JOIN ticketPackaging tp ON t.id = tp.ticketFk - JOIN client c ON c.id = t.clientFk - WHERE t.shipped BETWEEN '2017-11-21' AND ? - AND t.clientFk >= ? - AND (t.clientFk <= ? OR ? IS NULL) - AND c.isActive`; - return models.InvoiceOut.rawSql(query, [ - args.maxShipped, - args.fromClientId, - args.toClientId, - args.toClientId - ], options); - } - - async function getInvoiceableClients(ctx, options) { - const models = Self.app.models; - const args = ctx.args; - const minShipped = Date.vnNew(); - minShipped.setFullYear(minShipped.getFullYear() - 1); - - const query = `SELECT - c.id, - SUM(IFNULL - ( - s.quantity * - s.price * (100-s.discount)/100, - 0) - + IFNULL(ts.quantity * ts.price,0) - ) AS sumAmount, - c.hasToInvoiceByAddress, - c.email, - c.isToBeMailed, - a.id addressFk - FROM ticket t - LEFT JOIN sale s ON s.ticketFk = t.id - LEFT JOIN ticketService ts ON ts.ticketFk = t.id - JOIN address a ON a.id = t.addressFk - JOIN client c ON c.id = t.clientFk - WHERE ISNULL(t.refFk) AND c.id >= ? - AND (t.clientFk <= ? OR ? IS NULL) - AND t.shipped BETWEEN ? AND util.dayEnd(?) - AND t.companyFk = ? AND c.hasToInvoice - AND c.isTaxDataChecked AND c.isActive - GROUP BY c.id, IF(c.hasToInvoiceByAddress,a.id,TRUE) HAVING sumAmount > 0`; - - return models.InvoiceOut.rawSql(query, [ - args.fromClientId, - args.toClientId, - args.toClientId, - minShipped, - args.maxShipped, - args.companyFk - ], options); - } }; diff --git a/modules/invoiceOut/back/methods/invoiceOut/createPdf.js b/modules/invoiceOut/back/methods/invoiceOut/createPdf.js index 71e7c1543..23b6c9e04 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/createPdf.js +++ b/modules/invoiceOut/back/methods/invoiceOut/createPdf.js @@ -44,7 +44,7 @@ module.exports = Self => { try { const invoiceOut = await Self.findById(id, null, myOptions); const hasInvoicing = await models.Account.hasRole(userId, 'invoicing', myOptions); - console.log(invoiceOut, !hasInvoicing); + if (invoiceOut.hasPdf && !hasInvoicing) throw new UserError(`You don't have enough privileges`); @@ -56,7 +56,7 @@ module.exports = Self => { reference: invoiceOut.ref, recipientId: invoiceOut.clientFk }); - const stream = await invoiceReport.toPdfStream(); + const buffer = await invoiceReport.toPdfStream(); const issued = invoiceOut.issued; const year = issued.getFullYear().toString(); @@ -66,7 +66,7 @@ module.exports = Self => { const fileName = `${year}${invoiceOut.ref}.pdf`; // Store invoice - print.storage.write(stream, { + await print.storage.write(buffer, { type: 'invoice', path: `${year}/${month}/${day}`, fileName: fileName diff --git a/modules/invoiceOut/back/methods/invoiceOut/downloadZip.js b/modules/invoiceOut/back/methods/invoiceOut/downloadZip.js index 208d55358..fe005f1ab 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/downloadZip.js +++ b/modules/invoiceOut/back/methods/invoiceOut/downloadZip.js @@ -47,7 +47,6 @@ module.exports = Self => { ids = ids.split(','); for (let id of ids) { - console.log(zipConfig, totalSize, zipConfig ? zipConfig.maxSize : null); if (zipConfig && totalSize > zipConfig.maxSize) throw new UserError('Files are too large'); const invoiceOutPdf = await models.InvoiceOut.download(ctx, id, myOptions); const fileName = extractFileName(invoiceOutPdf[2]); diff --git a/modules/invoiceOut/back/methods/invoiceOut/exportationPdf.js b/modules/invoiceOut/back/methods/invoiceOut/exportationPdf.js index e947c5144..7a2526b35 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/exportationPdf.js +++ b/modules/invoiceOut/back/methods/invoiceOut/exportationPdf.js @@ -1,5 +1,3 @@ -const {Report} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('exportationPdf', { description: 'Returns the exportation pdf', @@ -39,17 +37,5 @@ module.exports = Self => { } }); - Self.exportationPdf = async(ctx, reference) => { - 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('exportation', params); - const stream = await report.toPdfStream(); - - return [stream, 'application/pdf', `filename="doc-${reference}.pdf"`]; - }; + Self.exportationPdf = (ctx, reference) => Self.printReport(ctx, reference, 'exportation'); }; diff --git a/modules/invoiceOut/back/methods/invoiceOut/getInvoiceDate.js b/modules/invoiceOut/back/methods/invoiceOut/getInvoiceDate.js new file mode 100644 index 000000000..dcc1fa6e8 --- /dev/null +++ b/modules/invoiceOut/back/methods/invoiceOut/getInvoiceDate.js @@ -0,0 +1,35 @@ +module.exports = Self => { + Self.remoteMethod('getInvoiceDate', { + description: 'Returns default Invoice Date', + accessType: 'READ', + accepts: [ + { + arg: 'companyFk', + type: 'number', + required: true + } + ], + returns: { + type: ['object'], + root: true + }, + http: { + path: `/getInvoiceDate`, + verb: 'GET' + } + }); + + Self.getInvoiceDate = async companyFk => { + const models = Self.app.models; + const [invoiceDate] = await models.InvoiceOut.rawSql( + `SELECT MAX(io.issued) issued + FROM invoiceOut io + JOIN invoiceOutSerial ios ON ios.code = io.serial + WHERE ios.type = 'global' + AND io.issued + AND io.companyFk = ?`, + [companyFk] + ); + return invoiceDate; + }; +}; diff --git a/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js b/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js index 95c51a96d..c8f8a6778 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js +++ b/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js @@ -1,43 +1,42 @@ +const UserError = require('vn-loopback/util/user-error'); + module.exports = Self => { Self.remoteMethodCtx('invoiceClient', { description: 'Make a invoice of a client', accessType: 'WRITE', - accepts: [{ - arg: 'clientId', - type: 'number', - description: 'The client id to invoice', - required: true - }, - { - arg: 'addressId', - type: 'number', - description: 'The address id to invoice', - required: true - }, - { - arg: 'invoiceDate', - type: 'date', - description: 'The invoice date', - required: true - }, - { - arg: 'maxShipped', - type: 'date', - description: 'The maximum shipped date', - required: true - }, - { - arg: 'companyFk', - type: 'number', - description: 'The company id to invoice', - required: true - }, - { - arg: 'minShipped', - type: 'date', - description: 'The minium shupped date', - required: true - }], + accepts: [ + { + arg: 'clientId', + type: 'number', + description: 'The client id to invoice', + required: true + }, { + arg: 'addressId', + type: 'number', + description: 'The address id to invoice', + required: true + }, { + arg: 'invoiceDate', + type: 'date', + description: 'The invoice date', + required: true + }, { + arg: 'maxShipped', + type: 'date', + description: 'The maximum shipped date', + required: true + }, { + arg: 'companyFk', + type: 'number', + description: 'The company id to invoice', + required: true + }, { + arg: 'printerFk', + type: 'number', + description: 'The printer to print', + required: true + } + ], returns: { type: 'object', root: true @@ -62,69 +61,65 @@ module.exports = Self => { myOptions.transaction = tx; } + const minShipped = Date.vnNew(); + minShipped.setFullYear(args.maxShipped.getFullYear() - 1); + let invoiceId; let invoiceOut; try { const client = await models.Client.findById(args.clientId, { fields: ['id', 'hasToInvoiceByAddress'] }, myOptions); - try { - if (client.hasToInvoiceByAddress) { - await Self.rawSql('CALL ticketToInvoiceByAddress(?, ?, ?, ?)', [ - args.minShipped, - args.maxShipped, - args.addressId, - args.companyFk - ], myOptions); - } else { - await Self.rawSql('CALL invoiceFromClient(?, ?, ?)', [ - args.maxShipped, - client.id, - args.companyFk - ], myOptions); - } - // Make invoice - const isSpanishCompany = await getIsSpanishCompany(args.companyFk, myOptions); - - // Validates ticket nagative base - const hasAnyNegativeBase = await getNegativeBase(myOptions); - if (hasAnyNegativeBase && isSpanishCompany) - return tx.rollback(); - - query = `SELECT invoiceSerial(?, ?, ?) AS serial`; - const [invoiceSerial] = await Self.rawSql(query, [ + if (client.hasToInvoiceByAddress) { + await Self.rawSql('CALL ticketToInvoiceByAddress(?, ?, ?, ?)', [ + minShipped, + args.maxShipped, + args.addressId, + args.companyFk + ], myOptions); + } else { + await Self.rawSql('CALL invoiceFromClient(?, ?, ?)', [ + args.maxShipped, client.id, - args.companyFk, - 'G' + args.companyFk ], myOptions); - const serialLetter = invoiceSerial.serial; - - query = `CALL invoiceOut_new(?, ?, NULL, @invoiceId)`; - await Self.rawSql(query, [ - serialLetter, - args.invoiceDate - ], myOptions); - - const [newInvoice] = await Self.rawSql(`SELECT @invoiceId id`, null, myOptions); - if (newInvoice.id) { - await Self.rawSql('CALL invoiceOutBooking(?)', [newInvoice.id], myOptions); - - invoiceId = newInvoice.id; - } - } catch (e) { - const failedClient = { - id: client.id, - stacktrace: e - }; - await notifyFailures(ctx, failedClient, myOptions); } - invoiceOut = await models.InvoiceOut.findById(invoiceId, { - include: { - relation: 'client' - } - }, myOptions); + // Make invoice + const isSpanishCompany = await getIsSpanishCompany(args.companyFk, myOptions); + + // Validates ticket nagative base + const hasAnyNegativeBase = await getNegativeBase(myOptions); + if (hasAnyNegativeBase && isSpanishCompany) + throw new UserError('Negative basis'); + + query = `SELECT invoiceSerial(?, ?, ?) AS serial`; + const [invoiceSerial] = await Self.rawSql(query, [ + client.id, + args.companyFk, + 'G' + ], myOptions); + const serialLetter = invoiceSerial.serial; + + query = `CALL invoiceOut_new(?, ?, NULL, @invoiceId)`; + await Self.rawSql(query, [ + serialLetter, + args.invoiceDate + ], myOptions); + + const [newInvoice] = await Self.rawSql(`SELECT @invoiceId id`, null, myOptions); + if (newInvoice.id) { + await Self.rawSql('CALL invoiceOutBooking(?)', [newInvoice.id], myOptions); + + invoiceOut = await models.InvoiceOut.findById(newInvoice.id, { + include: { + relation: 'client' + } + }, myOptions); + + invoiceId = newInvoice.id; + } if (tx) await tx.commit(); } catch (e) { @@ -132,15 +127,26 @@ module.exports = Self => { throw e; } - ctx.args = { - reference: invoiceOut.ref, - recipientId: invoiceOut.clientFk, - recipient: invoiceOut.client().email - }; - try { - await models.InvoiceOut.invoiceEmail(ctx, invoiceOut.ref); - } catch (err) {} - + if (invoiceId) { + if (!invoiceOut.client().isToBeMailed) { + const query = ` + CALL vn.report_print( + 'invoice', + ?, + account.myUser_getId(), + JSON_OBJECT('refFk', ?), + 'normal' + );`; + await models.InvoiceOut.rawSql(query, [args.printerFk, invoiceOut.ref]); + } else { + ctx.args = { + reference: invoiceOut.ref, + recipientId: invoiceOut.clientFk, + recipient: invoiceOut.client().email + }; + await models.InvoiceOut.invoiceEmail(ctx, invoiceOut.ref); + } + } return invoiceId; }; @@ -148,13 +154,12 @@ module.exports = Self => { const models = Self.app.models; const query = 'SELECT hasAnyNegativeBase() AS base'; const [result] = await models.InvoiceOut.rawSql(query, null, options); - return result && result.base; } async function getIsSpanishCompany(companyId, options) { const models = Self.app.models; - const query = `SELECT COUNT(*) AS total + const query = `SELECT COUNT(*) isSpanishCompany FROM supplier s JOIN country c ON c.id = s.countryFk AND c.code = 'ES' @@ -163,28 +168,6 @@ module.exports = Self => { companyId ], options); - return supplierCompany && supplierCompany.total; - } - - async function notifyFailures(ctx, failedClient, options) { - const models = Self.app.models; - const userId = ctx.req.accessToken.userId; - const $t = ctx.req.__; // $translate - - const worker = await models.EmailUser.findById(userId, null, options); - const subject = $t('Global invoicing failed'); - let body = $t(`Wasn't able to invoice the following clients`) + ':

'; - - body += `ID: ${failedClient.id} -
${failedClient.stacktrace}

`; - - await Self.rawSql(` - INSERT INTO vn.mail (sender, replyTo, sent, subject, body) - VALUES (?, ?, FALSE, ?, ?)`, [ - worker.email, - worker.email, - subject, - body - ], options); + return supplierCompany && supplierCompany.isSpanishCompany; } }; diff --git a/modules/invoiceOut/back/methods/invoiceOut/invoiceOutPdf.js b/modules/invoiceOut/back/methods/invoiceOut/invoiceOutPdf.js new file mode 100644 index 000000000..941d31596 --- /dev/null +++ b/modules/invoiceOut/back/methods/invoiceOut/invoiceOutPdf.js @@ -0,0 +1,50 @@ +const {Report} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('invoiceOutPdf', { + description: 'Returns the invoice pdf', + accessType: 'READ', + accepts: [ + { + arg: 'reference', + type: 'string', + required: true, + description: 'The invoice reference', + http: {source: 'path'} + } + ], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'String', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'String', + http: {target: 'header'} + } + ], + http: { + path: '/:reference/invoice-out-pdf', + verb: 'GET' + } + }); + + Self.invoiceOutPdf = async(ctx, reference) => { + 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('invoice', params); + const stream = await report.toPdfStream(); + + return [stream, 'application/pdf', `filename="doc-${reference}.pdf"`]; + }; +}; diff --git a/modules/invoiceOut/back/methods/invoiceOut/specs/filter.spec.js b/modules/invoiceOut/back/methods/invoiceOut/specs/filter.spec.js index 9264bf77d..15e3e887e 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/specs/filter.spec.js +++ b/modules/invoiceOut/back/methods/invoiceOut/specs/filter.spec.js @@ -65,7 +65,6 @@ describe('InvoiceOut filter()', () => { await invoiceOut.updateAttribute('hasPdf', true, options); const result = await models.InvoiceOut.filter(ctx, {id: invoiceOut.id}, options); - console.log(result); expect(result.length).toEqual(1); diff --git a/modules/invoiceOut/back/model-config.json b/modules/invoiceOut/back/model-config.json index 04933c4f0..b190126ea 100644 --- a/modules/invoiceOut/back/model-config.json +++ b/modules/invoiceOut/back/model-config.json @@ -8,6 +8,9 @@ "InvoiceContainer": { "dataSource": "invoiceStorage" }, + "Printer": { + "dataSource": "vn" + }, "TaxArea": { "dataSource": "vn" }, diff --git a/modules/invoiceOut/back/models/invoice-out.js b/modules/invoiceOut/back/models/invoice-out.js index 88adae2ef..6205abe7b 100644 --- a/modules/invoiceOut/back/models/invoice-out.js +++ b/modules/invoiceOut/back/models/invoice-out.js @@ -15,4 +15,6 @@ module.exports = Self => { require('../methods/invoiceOut/exportationPdf')(Self); require('../methods/invoiceOut/invoiceCsv')(Self); require('../methods/invoiceOut/invoiceCsvEmail')(Self); + require('../methods/invoiceOut/invoiceOutPdf')(Self); + require('../methods/invoiceOut/getInvoiceDate')(Self); }; diff --git a/modules/invoiceOut/back/models/printer.json b/modules/invoiceOut/back/models/printer.json new file mode 100644 index 000000000..99003560d --- /dev/null +++ b/modules/invoiceOut/back/models/printer.json @@ -0,0 +1,28 @@ +{ + "name": "Printer", + "base": "VnModel", + "options": { + "mysql": { + "table": "printer" + } + }, + "properties": { + "id": { + "type": "number", + "id": true, + "description": "Identifier" + }, + "name": { + "type": "string" + }, + "isLabeler": { + "type": "boolean" + } + }, + "acls": [{ + "accessType": "READ", + "principalType": "ROLE", + "principalId": "$everyone", + "permission": "ALLOW" + }] +} diff --git a/modules/invoiceOut/front/global-invoicing/index.html b/modules/invoiceOut/front/global-invoicing/index.html new file mode 100644 index 000000000..ebe46b84a --- /dev/null +++ b/modules/invoiceOut/front/global-invoicing/index.html @@ -0,0 +1,144 @@ + + + +
+
+ + Build packaging tickets + + + {{'Invoicing client' | translate}} {{$ctrl.currentAddress.clientId}} + + + Stopping process + + + Ended process + +
+
+ {{$ctrl.percentage | percentage: 0}} ({{$ctrl.addressNumber}} {{'of' | translate}} {{$ctrl.nAddresses}}) +
+
+
+ + + + + Id + Client + Address id + Street + Error + + + + + + + {{::error.address.clientId}} + + + + {{::error.address.clientName}} + + + {{::error.address.id}} + + + {{::error.address.nickname}} + + + {{::error.message}} + + + + + + + + + + +
+ + + + + + + + + {{::id}} - {{::name}} + + + + + + + + + + + + + + +
+
+ + + diff --git a/modules/invoiceOut/front/global-invoicing/index.js b/modules/invoiceOut/front/global-invoicing/index.js new file mode 100644 index 000000000..0aa6a4a24 --- /dev/null +++ b/modules/invoiceOut/front/global-invoicing/index.js @@ -0,0 +1,140 @@ +import ngModule from '../module'; +import Section from 'salix/components/section'; +import UserError from 'core/lib/user-error'; +import './style.scss'; + +class Controller extends Section { + $onInit() { + const date = Date.vnNew(); + Object.assign(this, { + maxShipped: new Date(date.getFullYear(), date.getMonth(), 0), + clientsToInvoice: 'all', + }); + + this.$http.get('UserConfigs/getUserConfig') + .then(res => { + this.companyFk = res.data.companyFk; + const params = { + companyFk: this.companyFk + }; + return this.$http.get('InvoiceOuts/getInvoiceDate', {params}); + }) + .then(res => { + this.minInvoicingDate = res.data.issued ? new Date(res.data.issued) : null; + this.invoiceDate = this.minInvoicingDate; + }); + } + + stopInvoicing() { + this.status = 'stopping'; + } + + makeInvoice() { + this.invoicing = true; + this.status = 'packageInvoicing'; + this.errors = []; + this.addresses = null; + + try { + if (this.clientsToInvoice == 'one' && !this.clientId) + throw new UserError('Choose a valid client'); + if (!this.invoiceDate || !this.maxShipped) + throw new UserError('Invoice date and the max date should be filled'); + if (this.invoiceDate < this.maxShipped) + throw new UserError('Invoice date can\'t be less than max date'); + if (this.invoiceDate.getTime() < this.minInvoicingDate.getTime()) + throw new UserError('Exists an invoice with a previous date'); + if (!this.companyFk) + throw new UserError('Choose a valid company'); + if (!this.printerFk) + throw new UserError('Choose a valid printer'); + + if (this.clientsToInvoice == 'all') + this.clientId = undefined; + + const params = { + invoiceDate: this.invoiceDate, + maxShipped: this.maxShipped, + clientId: this.clientId, + companyFk: this.companyFk + }; + this.$http.post(`InvoiceOuts/clientsToInvoice`, params) + .then(res => { + this.addresses = res.data; + if (!this.addresses.length) + throw new UserError(`There aren't tickets to invoice`); + + this.addressIndex = 0; + return this.invoiceOut(); + }) + .catch(err => this.handleError(err)); + } catch (err) { + this.handleError(err); + } + } + + handleError(err) { + this.invoicing = false; + this.status = null; + throw err; + } + + invoiceOut() { + if (this.addressIndex == this.addresses.length || this.status == 'stopping') { + this.invoicing = false; + this.status = 'done'; + return; + } + + this.status = 'invoicing'; + const address = this.addresses[this.addressIndex]; + this.currentAddress = address; + + const params = { + clientId: address.clientId, + addressId: address.id, + invoiceDate: this.invoiceDate, + maxShipped: this.maxShipped, + companyFk: this.companyFk, + printerFk: this.printerFk, + }; + + this.$http.post(`InvoiceOuts/invoiceClient`, params) + .then(() => this.invoiceNext()) + .catch(res => { + const message = res.data?.error?.message || res.message; + if (res.status >= 400 && res.status < 500) { + this.errors.unshift({address, message}); + this.invoiceNext(); + } else { + this.invoicing = false; + this.status = 'done'; + throw new UserError(`Critical invoicing error, proccess stopped`); + } + }) + } + + invoiceNext() { + this.addressIndex++; + this.invoiceOut(); + } + + get nAddresses() { + if (!this.addresses) return 0; + return this.addresses.length; + } + + get addressNumber() { + return Math.min(this.addressIndex + 1, this.nAddresses); + } + + get percentage() { + const len = this.nAddresses; + return Math.min(this.addressIndex, len) / len; + } +} + +ngModule.vnComponent('vnInvoiceOutGlobalInvoicing', { + template: require('./index.html'), + controller: Controller +}); diff --git a/modules/invoiceOut/front/global-invoicing/index.spec.js b/modules/invoiceOut/front/global-invoicing/index.spec.js new file mode 100644 index 000000000..056839b20 --- /dev/null +++ b/modules/invoiceOut/front/global-invoicing/index.spec.js @@ -0,0 +1,74 @@ +import './index'; + +describe('InvoiceOut', () => { + describe('Component vnInvoiceOutGlobalInvoicing', () => { + let controller; + let $httpBackend; + + beforeEach(ngModule('invoiceOut')); + + beforeEach(inject(($componentController, $rootScope, _$httpBackend_) => { + $httpBackend = _$httpBackend_; + const $scope = $rootScope.$new(); + const $element = angular.element(''); + + controller = $componentController('vnInvoiceOutGlobalInvoicing', {$element, $scope}); + })); + + describe('makeInvoice()', () => { + it('should throw an error when invoiceDate or maxShipped properties are not filled in', () => { + jest.spyOn(controller.vnApp, 'showError'); + controller.clientsToInvoice = 'all'; + + let error; + try { + controller.makeInvoice(); + } catch (e) { + error = e.message; + } + + const expectedError = 'Invoice date and the max date should be filled'; + + expect(error).toBe(expectedError); + }); + + it('should throw an error when select one client and clientId is not filled in', () => { + jest.spyOn(controller.vnApp, 'showError'); + controller.clientsToInvoice = 'one'; + + let error; + try { + controller.makeInvoice(); + } catch (e) { + error = e.message; + } + + const expectedError = 'Choose a valid client'; + + expect(error).toBe(expectedError); + }); + + it('should make an http POST query and then call to the showSuccess() method', () => { + const date = Date.vnNew(); + Object.assign(controller, { + invoiceDate: date, + maxShipped: date, + minInvoicingDate: date, + clientsToInvoice: 'one', + clientId: 1101, + companyFk: 442, + printerFk: 1 + }); + $httpBackend.expectPOST(`InvoiceOuts/clientsToInvoice`).respond([{ + clientId: 1101, + id: 121 + }]); + $httpBackend.expectPOST(`InvoiceOuts/invoiceClient`).respond(); + controller.makeInvoice(); + $httpBackend.flush(); + + expect(controller.status).toEqual('done'); + }); + }); + }); +}); diff --git a/modules/invoiceOut/front/global-invoicing/locale/es.yml b/modules/invoiceOut/front/global-invoicing/locale/es.yml new file mode 100644 index 000000000..5b1f7e883 --- /dev/null +++ b/modules/invoiceOut/front/global-invoicing/locale/es.yml @@ -0,0 +1,21 @@ +There aren't tickets to invoice: No existen tickets para facturar +Max date: Fecha límite +Invoice date: Fecha de factura +Invoice date can't be less than max date: La fecha de factura no puede ser inferior a la fecha límite +Invoice date and the max date should be filled: La fecha de factura y la fecha límite deben rellenarse +Choose a valid company: Selecciona un empresa válida +Choose a valid printer: Selecciona una impresora válida +All clients: Todos los clientes +Build packaging tickets: Generando tickets de embalajes +Address id: Id dirección +Printer: Impresora +of: de +Client: Cliente +Current client id: Id cliente actual +Invoicing client: Facturando cliente +Ended process: Proceso finalizado +Invoice out: Facturar +One client: Un solo cliente +Choose a valid client: Selecciona un cliente válido +Stop: Parar +Critical invoicing error, proccess stopped: Error crítico al facturar, proceso detenido \ No newline at end of file diff --git a/modules/invoiceOut/front/global-invoicing/style.scss b/modules/invoiceOut/front/global-invoicing/style.scss new file mode 100644 index 000000000..6fdfac0ba --- /dev/null +++ b/modules/invoiceOut/front/global-invoicing/style.scss @@ -0,0 +1,17 @@ +@import "variables"; + +vn-invoice-out-global-invoicing{ + + h5{ + color: $color-primary; + } + + #error { + line-break: normal; + overflow-wrap: break-word; + white-space: normal; + } + +} + + diff --git a/modules/invoiceOut/front/index.js b/modules/invoiceOut/front/index.js index 0307b2b4b..f7cebc0d0 100644 --- a/modules/invoiceOut/front/index.js +++ b/modules/invoiceOut/front/index.js @@ -9,4 +9,4 @@ import './descriptor'; import './descriptor-popover'; import './descriptor-menu'; import './index/manual'; -import './index/global-invoicing'; +import './global-invoicing'; diff --git a/modules/invoiceOut/front/index/global-invoicing/index.html b/modules/invoiceOut/front/index/global-invoicing/index.html deleted file mode 100644 index c2d1c4304..000000000 --- a/modules/invoiceOut/front/index/global-invoicing/index.html +++ /dev/null @@ -1,96 +0,0 @@ - - Create global invoice - - - - - - -
- -
- {{'Calculating packages to invoice...' | translate}} -
-
-
-
- -
- {{'Id Client' | translate}}: {{$ctrl.currentClientId}} - {{'of' | translate}} {{::$ctrl.lastClientId}} -
-
-
- - - - - - - - - - - - - - - {{::id}} - {{::name}} - - - {{::id}} - {{::name}} - - - - - - -
- - - {{$ctrl.isInvoicing}} - \ No newline at end of file diff --git a/modules/invoiceOut/front/index/global-invoicing/index.js b/modules/invoiceOut/front/index/global-invoicing/index.js deleted file mode 100644 index 0c5773adc..000000000 --- a/modules/invoiceOut/front/index/global-invoicing/index.js +++ /dev/null @@ -1,129 +0,0 @@ -import ngModule from '../../module'; -import Dialog from 'core/components/dialog'; -import './style.scss'; - -class Controller extends Dialog { - constructor($element, $, $transclude) { - super($element, $, $transclude); - this.invoice = { - maxShipped: Date.vnNew() - }; - this.clientsNumber = 'allClients'; - } - - $onInit() { - this.getMinClientId(); - this.getMaxClientId(); - } - - getMinClientId() { - this.getClientId('min') - .then(res => this.invoice.fromClientId = res.data.id); - } - - getMaxClientId() { - this.getClientId('max') - .then(res => this.invoice.toClientId = res.data.id); - } - - getClientId(func) { - const order = func == 'min' ? 'ASC' : 'DESC'; - const params = { - filter: { - order: 'id ' + order, - limit: 1 - } - }; - return this.$http.get('Clients/findOne', {params}); - } - - get companyFk() { - return this.invoice.companyFk; - } - - set companyFk(value) { - this.invoice.companyFk = value; - } - - restartValues() { - this.lastClientId = null; - this.$.invoiceButton.disabled = false; - } - - cancelRequest() { - this.canceler = this.$q.defer(); - return {timeout: this.canceler.promise}; - } - - invoiceOut(invoice, clientsAndAddresses) { - const [clientAndAddress] = clientsAndAddresses; - if (!clientAndAddress) return; - this.currentClientId = clientAndAddress.clientId; - const params = { - clientId: clientAndAddress.clientId, - addressId: clientAndAddress.addressId, - invoiceDate: invoice.invoiceDate, - maxShipped: invoice.maxShipped, - companyFk: invoice.companyFk, - minShipped: invoice.minShipped, - - }; - - const options = this.cancelRequest(); - - return this.$http.post(`InvoiceOuts/invoiceClient`, params, options) - .then(() => { - clientsAndAddresses.shift(); - return this.invoiceOut(invoice, clientsAndAddresses); - }); - } - - responseHandler(response) { - try { - if (response !== 'accept') - return super.responseHandler(response); - - if (!this.invoice.invoiceDate || !this.invoice.maxShipped) - throw new Error('Invoice date and the max date should be filled'); - - if (!this.invoice.fromClientId || !this.invoice.toClientId) - throw new Error('Choose a valid clients range'); - - this.on('close', () => { - if (this.canceler) this.canceler.resolve(); - this.vnApp.showSuccess(this.$t('Data saved!')); - }); - - this.$.invoiceButton.disabled = true; - this.packageInvoicing = true; - const options = this.cancelRequest(); - - this.$http.post(`InvoiceOuts/clientsToInvoice`, this.invoice, options) - .then(res => { - this.packageInvoicing = false; - const invoice = res.data.invoice; - const clientsAndAddresses = res.data.clientsAndAddresses; - if (!clientsAndAddresses.length) return super.responseHandler(response); - this.lastClientId = clientsAndAddresses[clientsAndAddresses.length - 1].clientId; - return this.invoiceOut(invoice, clientsAndAddresses); - }) - .then(() => super.responseHandler(response)) - .then(() => this.vnApp.showSuccess(this.$t('Data saved!'))) - .finally(() => this.restartValues()); - } catch (e) { - this.vnApp.showError(this.$t(e.message)); - this.restartValues(); - return false; - } - } -} - -Controller.$inject = ['$element', '$scope', '$transclude']; - -ngModule.vnComponent('vnInvoiceOutGlobalInvoicing', { - slotTemplate: require('./index.html'), - controller: Controller, - bindings: { - companyFk: ' { - describe('Component vnInvoiceOutGlobalInvoicing', () => { - let controller; - let $httpBackend; - let $httpParamSerializer; - - beforeEach(ngModule('invoiceOut')); - - beforeEach(inject(($componentController, $rootScope, _$httpBackend_, _$httpParamSerializer_) => { - $httpBackend = _$httpBackend_; - $httpParamSerializer = _$httpParamSerializer_; - let $scope = $rootScope.$new(); - const $element = angular.element(''); - const $transclude = { - $$boundTransclude: { - $$slots: [] - } - }; - controller = $componentController('vnInvoiceOutGlobalInvoicing', {$element, $scope, $transclude}); - controller.$.invoiceButton = {disabled: false}; - })); - - describe('getMinClientId()', () => { - it('should set the invoice fromClientId property', () => { - const filter = { - order: 'id ASC', - limit: 1 - }; - - const serializedParams = $httpParamSerializer({filter}); - $httpBackend.expectGET(`Clients/findOne?${serializedParams}`).respond(200, {id: 1101}); - - controller.getMinClientId(); - $httpBackend.flush(); - - expect(controller.invoice.fromClientId).toEqual(1101); - }); - }); - - describe('getMaxClientId()', () => { - it('should set the invoice toClientId property', () => { - const filter = { - order: 'id DESC', - limit: 1 - }; - - const serializedParams = $httpParamSerializer({filter}); - $httpBackend.expectGET(`Clients/findOne?${serializedParams}`).respond(200, {id: 1112}); - - controller.getMaxClientId(); - $httpBackend.flush(); - - expect(controller.invoice.toClientId).toEqual(1112); - }); - }); - - describe('responseHandler()', () => { - it('should throw an error when invoiceDate or maxShipped properties are not filled in', () => { - jest.spyOn(controller.vnApp, 'showError'); - - controller.invoice = { - fromClientId: 1101, - toClientId: 1101 - }; - - controller.responseHandler('accept'); - - const expectedError = 'Invoice date and the max date should be filled'; - - expect(controller.vnApp.showError).toHaveBeenCalledWith(expectedError); - }); - - it('should throw an error when fromClientId or toClientId properties are not filled in', () => { - jest.spyOn(controller.vnApp, 'showError'); - - controller.invoice = { - invoiceDate: Date.vnNew(), - maxShipped: Date.vnNew() - }; - - controller.responseHandler('accept'); - - expect(controller.vnApp.showError).toHaveBeenCalledWith(`Choose a valid clients range`); - }); - - it('should make an http POST query and then call to the showSuccess() method', () => { - jest.spyOn(controller.vnApp, 'showSuccess'); - - const minShipped = Date.vnNew(); - minShipped.setFullYear(minShipped.getFullYear() - 1); - minShipped.setMonth(1); - minShipped.setDate(1); - minShipped.setHours(0, 0, 0, 0); - controller.invoice = { - invoiceDate: Date.vnNew(), - maxShipped: Date.vnNew(), - fromClientId: 1101, - toClientId: 1101, - companyFk: 442, - minShipped: minShipped - }; - const response = { - clientsAndAddresses: [{clientId: 1101, addressId: 121}], - invoice: controller.invoice - }; - - $httpBackend.expect('POST', `InvoiceOuts/clientsToInvoice`).respond(response); - $httpBackend.expect('POST', `InvoiceOuts/invoiceClient`).respond({id: 1}); - controller.responseHandler('accept'); - $httpBackend.flush(); - - expect(controller.vnApp.showSuccess).toHaveBeenCalled(); - }); - }); - }); -}); diff --git a/modules/invoiceOut/front/index/global-invoicing/locale/es.yml b/modules/invoiceOut/front/index/global-invoicing/locale/es.yml deleted file mode 100644 index af151684f..000000000 --- a/modules/invoiceOut/front/index/global-invoicing/locale/es.yml +++ /dev/null @@ -1,14 +0,0 @@ -Create global invoice: Crear factura global -Some fields are required: Algunos campos son obligatorios -Max date: Fecha límite -Adding invoices to queue...: Añadiendo facturas a la cola... -Invoice date: Fecha de factura -From client: Desde el cliente -To client: Hasta el cliente -Invoice date and the max date should be filled: La fecha de factura y la fecha límite deben rellenarse -Choose a valid clients range: Selecciona un rango válido de clientes -of: de -Id Client: Id Cliente -All clients: Todos los clientes -Clients range: Rango de clientes -Calculating packages to invoice...: Calculando paquetes a factura... \ No newline at end of file diff --git a/modules/invoiceOut/front/index/global-invoicing/style.scss b/modules/invoiceOut/front/index/global-invoicing/style.scss deleted file mode 100644 index d0bd9e214..000000000 --- a/modules/invoiceOut/front/index/global-invoicing/style.scss +++ /dev/null @@ -1,17 +0,0 @@ -@import "variables"; - -.vn-invoice-out-global-invoicing { - tpl-body { - width: 500px; - - .progress { - font-weight: bold; - text-align: center; - font-size: 1.5rem; - color: $color-primary; - vn-horizontal { - justify-content: center - } - } - } -} \ No newline at end of file diff --git a/modules/invoiceOut/front/index/index.html b/modules/invoiceOut/front/index/index.html index e2cf2120a..dc4d5d8a9 100644 --- a/modules/invoiceOut/front/index/index.html +++ b/modules/invoiceOut/front/index/index.html @@ -18,7 +18,7 @@ - @@ -37,7 +37,7 @@ class="clickable vn-tr search-result" ui-sref="invoiceOut.card.summary({id: {{::invoiceOut.id}}})"> - @@ -68,29 +68,13 @@
- - - - - - - Manual invoicing - - - Global invoicing - - - + +
- - \ No newline at end of file diff --git a/modules/invoiceOut/front/index/manual/index.html b/modules/invoiceOut/front/index/manual/index.html index 3148d3f94..37e6fa119 100644 --- a/modules/invoiceOut/front/index/manual/index.html +++ b/modules/invoiceOut/front/index/manual/index.html @@ -14,11 +14,11 @@ data="taxAreas" order="code"> -
- + Invoicing in progress...
@@ -80,4 +80,4 @@ - \ No newline at end of file + diff --git a/modules/invoiceOut/front/index/manual/style.scss b/modules/invoiceOut/front/index/manual/style.scss index 18e6f3513..820c07756 100644 --- a/modules/invoiceOut/front/index/manual/style.scss +++ b/modules/invoiceOut/front/index/manual/style.scss @@ -14,4 +14,4 @@ } } } -} \ No newline at end of file +} diff --git a/modules/invoiceOut/front/routes.json b/modules/invoiceOut/front/routes.json index 09d9f3d33..c396a5334 100644 --- a/modules/invoiceOut/front/routes.json +++ b/modules/invoiceOut/front/routes.json @@ -6,7 +6,9 @@ "dependencies": ["worker", "client", "ticket"], "menus": { "main": [ - {"state": "invoiceOut.index", "icon": "icon-invoice-out"} + {"state": "invoiceOut.index", "icon": "icon-invoice-out"}, + {"state": "invoiceOut.global-invoicing", "icon": "contact_support"} + ] }, "routes": [ @@ -24,6 +26,12 @@ "component": "vn-invoice-out-index", "description": "InvoiceOut" }, + { + "url": "/global-invoicing?q", + "state": "invoiceOut.global-invoicing", + "component": "vn-invoice-out-global-invoicing", + "description": "Global invoicing" + }, { "url": "/summary", "state": "invoiceOut.card.summary", @@ -40,4 +48,4 @@ "component": "vn-invoice-out-card" } ] -} \ No newline at end of file +} diff --git a/modules/item/back/methods/fixed-price/editFixedPrice.js b/modules/item/back/methods/fixed-price/editFixedPrice.js new file mode 100644 index 000000000..13e0fc41b --- /dev/null +++ b/modules/item/back/methods/fixed-price/editFixedPrice.js @@ -0,0 +1,96 @@ +module.exports = Self => { + Self.remoteMethodCtx('editFixedPrice', { + description: 'Updates a column for one or more fixed price', + accessType: 'WRITE', + accepts: [{ + arg: 'field', + type: 'string', + required: true, + description: `the column to edit` + }, + { + arg: 'newValue', + type: 'any', + required: true, + description: `The new value to save` + }, + { + arg: 'lines', + type: ['object'], + required: true, + description: `the buys which will be modified` + }, + { + arg: 'filter', + type: 'object', + description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string' + }], + returns: { + type: 'object', + root: true + }, + http: { + path: `/editFixedPrice`, + verb: 'POST' + } + }); + + Self.editFixedPrice = async(ctx, field, newValue, lines, filter, options) => { + let tx; + const myOptions = {}; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + if (!myOptions.transaction) { + tx = await Self.beginTransaction({}); + myOptions.transaction = tx; + } + + let modelName; + let identifier; + + switch (field) { + case 'hasMinPrice': + case 'minPrice': + modelName = 'Item'; + identifier = 'itemFk'; + break; + case 'rate2': + case 'rate3': + case 'started': + case 'ended': + case 'warehouseFk': + modelName = 'FixedPrice'; + identifier = 'id'; + } + + const models = Self.app.models; + const model = models[modelName]; + try { + const promises = []; + const value = {}; + value[field] = newValue; + + if (filter) { + filter = {where: filter}; + lines = await models.FixedPrice.filter(ctx, filter, myOptions); + } + + const targets = lines.map(line => { + return line[identifier]; + }); + for (let target of targets) + promises.push(model.upsertWithWhere({id: target}, value, myOptions)); + + const result = await Promise.all(promises); + + if (tx) await tx.commit(); + + return result; + } catch (e) { + if (tx) await tx.rollback(); + throw e; + } + }; +}; diff --git a/modules/item/back/methods/fixed-price/filter.js b/modules/item/back/methods/fixed-price/filter.js index c15ae67f0..9c91886c1 100644 --- a/modules/item/back/methods/fixed-price/filter.js +++ b/modules/item/back/methods/fixed-price/filter.js @@ -184,8 +184,7 @@ module.exports = Self => { } } - stmt.merge(conn.makeWhere(filter.where)); - stmt.merge(conn.makePagination(filter)); + stmt.merge(conn.makeSuffix(filter)); const fixedPriceIndex = stmts.push(stmt) - 1; const sql = ParameterizedSQL.join(stmts, ';'); diff --git a/modules/item/back/methods/fixed-price/specs/editFixedPrice.spec.js b/modules/item/back/methods/fixed-price/specs/editFixedPrice.spec.js new file mode 100644 index 000000000..9c265f28a --- /dev/null +++ b/modules/item/back/methods/fixed-price/specs/editFixedPrice.spec.js @@ -0,0 +1,63 @@ +const models = require('vn-loopback/server/server').models; + +describe('Item editFixedPrice()', () => { + it('should change the value of a given column for the selected buys', async() => { + const tx = await models.FixedPrice.beginTransaction({}); + const options = {transaction: tx}; + + try { + const ctx = { + args: { + search: '1' + }, + req: {accessToken: {userId: 1}} + }; + + const [original] = await models.FixedPrice.filter(ctx, null, options); + + const field = 'rate2'; + const newValue = 99; + const lines = [{itemFk: original.itemFk, id: original.id}]; + + await models.FixedPrice.editFixedPrice(ctx, field, newValue, lines, null, options); + + const [result] = await models.FixedPrice.filter(ctx, null, options); + + expect(result[field]).toEqual(newValue); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + + it('should change the value of a given column for filter', async() => { + const tx = await models.FixedPrice.beginTransaction({}); + const options = {transaction: tx}; + + try { + const filter = {'it.categoryFk': 1}; + const ctx = { + args: { + filter: filter + }, + req: {accessToken: {userId: 1}} + }; + + const field = 'rate2'; + const newValue = 88; + + await models.FixedPrice.editFixedPrice(ctx, field, newValue, null, filter, options); + + const [result] = await models.FixedPrice.filter(ctx, filter, options); + + expect(result[field]).toEqual(newValue); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); +}); diff --git a/modules/item/back/methods/fixed-price/specs/upsertFixedPrice.spec.js b/modules/item/back/methods/fixed-price/specs/upsertFixedPrice.spec.js index 5a47de6bf..823406500 100644 --- a/modules/item/back/methods/fixed-price/specs/upsertFixedPrice.spec.js +++ b/modules/item/back/methods/fixed-price/specs/upsertFixedPrice.spec.js @@ -1,4 +1,5 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('upsertFixedPrice()', () => { const now = Date.vnNew(); @@ -7,6 +8,17 @@ describe('upsertFixedPrice()', () => { beforeAll(async() => { originalFixedPrice = await models.FixedPrice.findById(fixedPriceId); + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); }); it(`should toggle the hasMinPrice boolean if there's a minPrice and update the rest of the data`, async() => { @@ -30,7 +42,7 @@ describe('upsertFixedPrice()', () => { delete ctx.args.started; delete ctx.args.ended; - ctx.args.hasMinPrice = true; + ctx.args.hasMinPrice = false; expect(result).toEqual(jasmine.objectContaining(ctx.args)); @@ -62,7 +74,7 @@ describe('upsertFixedPrice()', () => { delete ctx.args.started; delete ctx.args.ended; - ctx.args.hasMinPrice = false; + ctx.args.hasMinPrice = true; expect(result).toEqual(jasmine.objectContaining(ctx.args)); @@ -93,7 +105,7 @@ describe('upsertFixedPrice()', () => { rate2: rate2, rate3: firstRate3, minPrice: 0, - hasMinPrice: false + hasMinPrice: true }}; // create new fixed price diff --git a/modules/item/back/methods/fixed-price/upsertFixedPrice.js b/modules/item/back/methods/fixed-price/upsertFixedPrice.js index eb3eec1bd..edbd23604 100644 --- a/modules/item/back/methods/fixed-price/upsertFixedPrice.js +++ b/modules/item/back/methods/fixed-price/upsertFixedPrice.js @@ -87,7 +87,7 @@ module.exports = Self => { await targetItem.updateAttributes({ minPrice: args.minPrice, - hasMinPrice: args.minPrice ? true : false + hasMinPrice: args.hasMinPrice }, myOptions); const itemFields = [ diff --git a/modules/item/back/methods/item-image-queue/download.js b/modules/item/back/methods/item-image-queue/download.js new file mode 100644 index 000000000..eb952daa4 --- /dev/null +++ b/modules/item/back/methods/item-image-queue/download.js @@ -0,0 +1,92 @@ +const axios = require('axios'); +const fs = require('fs/promises'); +const {createWriteStream} = require('fs'); +const path = require('path'); + +module.exports = Self => { + Self.remoteMethod('download', { + description: 'Processes the image download queue', + accessType: 'WRITE', + http: { + path: `/download`, + verb: 'POST', + }, + }); + + Self.download = async() => { + const models = Self.app.models; + const tempContainer = await models.TempContainer.container( + 'salix-image' + ); + const tempPath = path.join( + tempContainer.client.root, + tempContainer.name + ); + const maxAttempts = 3; + const collectionName = 'catalog'; + + let tempFilePath; + let queueRow; + try { + queueRow = await Self.findOne( + { + fields: ['id', 'itemFk', 'url', 'attempts'], + where: { + url: {neq: null}, + attempts: { + lt: maxAttempts, + }, + }, + order: 'priority, attempts, updated', + } + ); + + if (!queueRow) return; + + const fileName = `${queueRow.itemFk}.png`; + tempFilePath = path.join(tempPath, fileName); + + // Download remote image + const response = await axios.get(queueRow.url, { + responseType: 'stream', + }); + + const writeStream = createWriteStream(tempFilePath); + await new Promise((resolve, reject) => { + writeStream.on('open', () => response.data.pipe(writeStream)); + writeStream.on('finish', () => resolve()); + writeStream.on('error', error => reject(error)); + }); + + await models.Image.resize({ + collectionName: collectionName, + srcFile: tempFilePath, + fileName: fileName, + entityId: queueRow.itemFk + }); + + try { + await fs.unlink(tempFilePath); + } catch (error) { } + + await queueRow.destroy(); + + // Restart queue + Self.download(); + } catch (error) { + if (queueRow.attempts < maxAttempts) { + await queueRow.updateAttributes({ + error: error, + attempts: queueRow.attempts + 1, + updated: Date.vnNew(), + }); + } + + try { + await fs.unlink(tempFilePath); + } catch (error) { } + + Self.download(); + } + }; +}; diff --git a/modules/item/back/methods/item-image-queue/downloadImages.js b/modules/item/back/methods/item-image-queue/downloadImages.js deleted file mode 100644 index c4d7f4b98..000000000 --- a/modules/item/back/methods/item-image-queue/downloadImages.js +++ /dev/null @@ -1,105 +0,0 @@ -const https = require('https'); -const fs = require('fs-extra'); -const path = require('path'); -const uuid = require('uuid'); - -module.exports = Self => { - Self.remoteMethod('downloadImages', { - description: 'Returns last entries', - accessType: 'WRITE', - returns: { - type: ['Object'], - root: true - }, - http: { - path: `/downloadImages`, - verb: 'POST' - } - }); - - Self.downloadImages = async() => { - const models = Self.app.models; - const container = await models.TempContainer.container('salix-image'); - const tempPath = path.join(container.client.root, container.name); - const maxAttempts = 3; - - const images = await Self.find({ - where: {attempts: {eq: maxAttempts}} - }); - - for (let image of images) { - const currentStamp = Date.vnNew().getTime(); - const updatedStamp = image.updated.getTime(); - const graceTime = Math.abs(currentStamp - updatedStamp); - const maxTTL = 3600 * 48 * 1000; // 48 hours in ms; - - if (graceTime >= maxTTL) - await Self.destroyById(image.itemFk); - } - - download(); - - async function download() { - const image = await Self.findOne({ - where: {url: {neq: null}, attempts: {lt: maxAttempts}}, - order: 'priority, attempts, updated' - }); - - if (!image) return; - - const fileName = `${uuid.v4()}.png`; - const filePath = path.join(tempPath, fileName); - const imageUrl = image.url.replace('http://', 'https://'); - - https.get(imageUrl, async response => { - if (response.statusCode != 200) { - const error = new Error(`Could not download the image. Status code ${response.statusCode}`); - - return await errorHandler(image.itemFk, error, filePath); - } - - const writeStream = fs.createWriteStream(filePath); - writeStream.on('open', () => response.pipe(writeStream)); - writeStream.on('error', async error => - await errorHandler(image.itemFk, error, filePath)); - writeStream.on('finish', writeStream.end()); - - writeStream.on('close', async function() { - try { - await models.Image.registerImage('catalog', filePath, fileName, image.itemFk); - await image.destroy(); - - download(); - } catch (error) { - await errorHandler(image.itemFk, error, filePath); - } - }); - }).on('error', async error => { - await errorHandler(image.itemFk, error, filePath); - }); - } - - async function errorHandler(rowId, error, filePath) { - try { - const row = await Self.findById(rowId); - - if (!row) return; - - if (row.attempts < maxAttempts) { - await row.updateAttributes({ - error: error, - attempts: row.attempts + 1, - updated: Date.vnNew() - }); - } - - if (filePath && fs.existsSync(filePath)) - await fs.unlink(filePath); - - download(); - } catch (err) { - throw new Error(`Image download failed: ${err}`); - } - } - }; -}; diff --git a/modules/item/back/methods/item/labelPdf.js b/modules/item/back/methods/item/labelPdf.js index 747869b37..c2462353d 100644 --- a/modules/item/back/methods/item/labelPdf.js +++ b/modules/item/back/methods/item/labelPdf.js @@ -1,5 +1,3 @@ -const {Report} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('labelPdf', { description: 'Returns the item label pdf', @@ -56,17 +54,5 @@ module.exports = Self => { } }); - Self.labelPdf = 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('item-label', params); - const stream = await report.toPdfStream(); - - return [stream, 'application/pdf', `filename="item-${id}.pdf"`]; - }; + Self.labelPdf = (ctx, id) => Self.printReport(ctx, id, 'item-label'); }; diff --git a/modules/item/back/methods/item/specs/clone.spec.js b/modules/item/back/methods/item/specs/clone.spec.js index 1f4a87ac1..01210677e 100644 --- a/modules/item/back/methods/item/specs/clone.spec.js +++ b/modules/item/back/methods/item/specs/clone.spec.js @@ -1,7 +1,21 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('item clone()', () => { let nextItemId; + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); beforeEach(async() => { let query = `SELECT i1.id + 1 as id FROM vn.item i1 diff --git a/modules/item/back/methods/item/specs/new.spec.js b/modules/item/back/methods/item/specs/new.spec.js index e34ab2cf5..a1c741649 100644 --- a/modules/item/back/methods/item/specs/new.spec.js +++ b/modules/item/back/methods/item/specs/new.spec.js @@ -1,6 +1,21 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('item new()', () => { + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); + it('should create a new item, adding the name as a tag', async() => { const tx = await models.Item.beginTransaction({}); const options = {transaction: tx}; diff --git a/modules/item/back/methods/item/specs/regularize.spec.js b/modules/item/back/methods/item/specs/regularize.spec.js index ea0cdfa5a..e7df9a003 100644 --- a/modules/item/back/methods/item/specs/regularize.spec.js +++ b/modules/item/back/methods/item/specs/regularize.spec.js @@ -1,6 +1,21 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('regularize()', () => { + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 18}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); + it('should create a new ticket and add a line', async() => { const tx = await models.Item.beginTransaction({}); const options = {transaction: tx}; diff --git a/modules/item/back/methods/item/specs/updateTaxes.spec.js b/modules/item/back/methods/item/specs/updateTaxes.spec.js index 66d2ce81c..793e43de8 100644 --- a/modules/item/back/methods/item/specs/updateTaxes.spec.js +++ b/modules/item/back/methods/item/specs/updateTaxes.spec.js @@ -1,6 +1,21 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('item updateTaxes()', () => { + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); + it('should throw an error if the taxClassFk is blank', async() => { const tx = await models.Item.beginTransaction({}); const options = {transaction: tx}; diff --git a/modules/item/back/methods/tag/specs/onSubmit.spec.js b/modules/item/back/methods/tag/specs/onSubmit.spec.js index f24aad7e4..1e96d9e81 100644 --- a/modules/item/back/methods/tag/specs/onSubmit.spec.js +++ b/modules/item/back/methods/tag/specs/onSubmit.spec.js @@ -1,6 +1,21 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('tag onSubmit()', () => { + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); + it('should delete a tag', async() => { const tx = await models.Item.beginTransaction({}); const options = {transaction: tx}; diff --git a/modules/item/back/models/fixed-price.js b/modules/item/back/models/fixed-price.js index 91010805f..45f8d79ef 100644 --- a/modules/item/back/models/fixed-price.js +++ b/modules/item/back/models/fixed-price.js @@ -2,4 +2,5 @@ module.exports = Self => { require('../methods/fixed-price/filter')(Self); require('../methods/fixed-price/upsertFixedPrice')(Self); require('../methods/fixed-price/getRate2')(Self); + require('../methods/fixed-price/editFixedPrice')(Self); }; diff --git a/modules/item/back/models/item-barcode.json b/modules/item/back/models/item-barcode.json index e2ce347cb..12068a65f 100644 --- a/modules/item/back/models/item-barcode.json +++ b/modules/item/back/models/item-barcode.json @@ -1,11 +1,6 @@ { "name": "ItemBarcode", "base": "Loggable", - "log": { - "model": "ItemLog", - "relation": "item", - "showField": "code" - }, "options": { "mysql": { "table": "itemBarcode" @@ -27,6 +22,6 @@ "type": "belongsTo", "model": "Item", "foreignKey": "itemFk" - } + } } } diff --git a/modules/item/back/models/item-botanical.json b/modules/item/back/models/item-botanical.json index 8d8fd389f..8a8bba870 100644 --- a/modules/item/back/models/item-botanical.json +++ b/modules/item/back/models/item-botanical.json @@ -1,10 +1,6 @@ { "name": "ItemBotanical", "base": "Loggable", - "log": { - "model": "ItemLog", - "relation": "item" - }, "options": { "mysql": { "table": "itemBotanical" @@ -34,4 +30,4 @@ "foreignKey": "specieFk" } } -} \ No newline at end of file +} diff --git a/modules/item/back/models/item-image-queue.js b/modules/item/back/models/item-image-queue.js index e2059ddac..35a467693 100644 --- a/modules/item/back/models/item-image-queue.js +++ b/modules/item/back/models/item-image-queue.js @@ -1,3 +1,3 @@ module.exports = Self => { - require('../methods/item-image-queue/downloadImages')(Self); + require('../methods/item-image-queue/download')(Self); }; diff --git a/modules/item/back/models/item-shelving.json b/modules/item/back/models/item-shelving.json index 0890350da..339b9ab6e 100644 --- a/modules/item/back/models/item-shelving.json +++ b/modules/item/back/models/item-shelving.json @@ -20,6 +20,9 @@ }, "created": { "type": "date" + }, + "isChecked": { + "type": "boolean" } }, "relations": { diff --git a/modules/item/back/models/item-tag.json b/modules/item/back/models/item-tag.json index 5660b3628..0742f8d3f 100644 --- a/modules/item/back/models/item-tag.json +++ b/modules/item/back/models/item-tag.json @@ -1,11 +1,6 @@ { "name": "ItemTag", "base": "Loggable", - "log": { - "model": "ItemLog", - "relation": "item", - "showField": "value" - }, "options": { "mysql": { "table": "itemTag" diff --git a/modules/item/back/models/item-tax-country.json b/modules/item/back/models/item-tax-country.json index f10a9eb72..002be97d8 100644 --- a/modules/item/back/models/item-tax-country.json +++ b/modules/item/back/models/item-tax-country.json @@ -1,11 +1,6 @@ { "name": "ItemTaxCountry", "base": "Loggable", - "log": { - "model": "ItemLog", - "relation": "item", - "showField": "countryFk" - }, "options": { "mysql": { "table": "itemTaxCountry" @@ -47,4 +42,4 @@ "foreignKey": "taxClassFk" } } -} \ No newline at end of file +} diff --git a/modules/item/back/models/item.json b/modules/item/back/models/item.json index 10300f7a1..4a7e04002 100644 --- a/modules/item/back/models/item.json +++ b/modules/item/back/models/item.json @@ -1,10 +1,6 @@ { "name": "Item", "base": "Loggable", - "log": { - "model": "ItemLog", - "showField": "id" - }, "options": { "mysql": { "table": "item" @@ -220,4 +216,4 @@ } } } -} \ No newline at end of file +} diff --git a/modules/item/front/fixed-price/index.html b/modules/item/front/fixed-price/index.html index ce7cefe7a..a82fd2742 100644 --- a/modules/item/front/fixed-price/index.html +++ b/modules/item/front/fixed-price/index.html @@ -1,6 +1,7 @@ @@ -31,15 +34,21 @@ + - + + - + @@ -80,7 +81,7 @@ @@ -169,12 +170,20 @@ class="link"> {{ticket.refFk}} - {{ticket.state}} + + @@ -107,6 +110,7 @@ {{::travel.cargoSupplierNickname}} + + - + - - + + diff --git a/modules/travel/front/extra-community/index.js b/modules/travel/front/extra-community/index.js index 920339469..2028c9c19 100644 --- a/modules/travel/front/extra-community/index.js +++ b/modules/travel/front/extra-community/index.js @@ -141,8 +141,11 @@ class Controller extends Section { get reportParams() { const userParams = this.$.model.userParams; + const currentFilter = this.$.model.currentFilter; + return Object.assign({ - authorization: this.vnToken.token + authorization: this.vnToken.token, + filter: currentFilter }, userParams); } diff --git a/modules/travel/front/extra-community/locale/es.yml b/modules/travel/front/extra-community/locale/es.yml index dc231226f..ed6179c91 100644 --- a/modules/travel/front/extra-community/locale/es.yml +++ b/modules/travel/front/extra-community/locale/es.yml @@ -6,6 +6,6 @@ Phy. KG: KG físico Vol. KG: KG Vol. Search by travel id or reference: Buscar por id de travel o referencia Search by extra community travel: Buscar por envío extra comunitario -Continent Out: Continente salida +Continent Out: Cont. salida W. Shipped: F. envío -W. Landed: F. llegada \ No newline at end of file +W. Landed: F. llegada diff --git a/modules/travel/front/index/index.html b/modules/travel/front/index/index.html index 27a700083..a768e4a29 100644 --- a/modules/travel/front/index/index.html +++ b/modules/travel/front/index/index.html @@ -2,6 +2,15 @@ + + + + @@ -9,23 +18,22 @@ - Id Reference Agency Warehouse Out Shipped - Delivered + Warehouse In Landed - Received + + Total entries - - {{::travel.id}} {{::travel.ref}} {{::travel.agencyModeName}} {{::travel.warehouseOutName}} @@ -34,14 +42,27 @@ {{::travel.shipped | date:'dd/MM/yyyy'}} - + + + + {{::travel.warehouseInName}} {{::travel.landed | date:'dd/MM/yyyy'}} - + + + + + {{::travel.totalEntries}} - @@ -78,38 +99,9 @@ fixed-bottom-right> - - - - - Filter by selection - - - Exclude selection - - - Remove filter - - - Remove all filters - - - Copy value - - - \ No newline at end of file diff --git a/modules/travel/front/index/index.js b/modules/travel/front/index/index.js index 7701289b7..a570146fe 100644 --- a/modules/travel/front/index/index.js +++ b/modules/travel/front/index/index.js @@ -1,5 +1,6 @@ import ngModule from '../module'; import Section from 'salix/components/section'; +import './style.scss'; export default class Controller extends Section { preview(travel) { @@ -30,37 +31,6 @@ export default class Controller extends Section { if (timeDifference == 0) return 'warning'; if (timeDifference < 0) return 'success'; } - - exprBuilder(param, value) { - switch (param) { - case 'search': - return /^\d+$/.test(value) - ? {'t.id': value} - : {'t.ref': {like: `%${value}%`}}; - case 'ref': - return {'t.ref': {like: `%${value}%`}}; - case 'shipped': - return {'t.shipped': {between: this.dateRange(value)}}; - case 'landed': - return {'t.landed': {between: this.dateRange(value)}}; - case 'id': - case 'agencyModeFk': - case 'warehouseOutFk': - case 'warehouseInFk': - case 'totalEntries': - param = `t.${param}`; - return {[param]: value}; - } - } - - dateRange(value) { - const minHour = new Date(value); - minHour.setHours(0, 0, 0, 0); - const maxHour = new Date(value); - maxHour.setHours(23, 59, 59, 59); - - return [minHour, maxHour]; - } } ngModule.vnComponent('vnTravelIndex', { diff --git a/modules/travel/front/index/style.scss b/modules/travel/front/index/style.scss new file mode 100644 index 000000000..ca1cf538b --- /dev/null +++ b/modules/travel/front/index/style.scss @@ -0,0 +1,11 @@ +@import "variables"; + +vn-travel-index { + vn-icon { + color: $color-font-secondary + } + + vn-icon.active { + color: $color-success + } +} diff --git a/modules/travel/front/locale/es.yml b/modules/travel/front/locale/es.yml index 7231d37cd..043702b99 100644 --- a/modules/travel/front/locale/es.yml +++ b/modules/travel/front/locale/es.yml @@ -1,7 +1,7 @@ #Ordenar alfabeticamente Reference: Referencia -Warehouse Out: Almacén salida -Warehouse In: Almacén llegada +Warehouse Out: Alm salida +Warehouse In: Alm llegada Shipped from: Salida desde Shipped to: Salida hasta Landed from: Llegada desde @@ -10,12 +10,12 @@ Shipped: F. salida Landed: F. llegada Delivered: Enviado Received: Recibido -Travel id: Id envío -Search travels by id: Buscar envíos por identificador +Travel id: Id +Search travels by id: Buscar envíos por identificador o referencia New travel: Nuevo envío travel: envío # Sections Travels: Envíos Log: Historial -Thermographs: Termógrafos \ No newline at end of file +Thermographs: Termógrafos diff --git a/modules/travel/front/main/index.html b/modules/travel/front/main/index.html index feb1e8b01..131d9409e 100644 --- a/modules/travel/front/main/index.html +++ b/modules/travel/front/main/index.html @@ -1,20 +1,6 @@ - - - - - \ No newline at end of file + diff --git a/modules/travel/front/main/index.js b/modules/travel/front/main/index.js index fbaf78c16..6a153f21a 100644 --- a/modules/travel/front/main/index.js +++ b/modules/travel/front/main/index.js @@ -4,28 +4,6 @@ import ModuleMain from 'salix/components/module-main'; export default class Travel extends ModuleMain { constructor() { super(); - - this.filterParams = { - scopeDays: 1 - }; - } - - fetchParams($params) { - if (!Object.entries($params).length) - $params.scopeDays = 1; - - if (typeof $params.scopeDays === 'number') { - const shippedFrom = Date.vnNew(); - shippedFrom.setHours(0, 0, 0, 0); - - const shippedTo = new Date(shippedFrom.getTime()); - shippedTo.setDate(shippedTo.getDate() + $params.scopeDays); - shippedTo.setHours(23, 59, 59, 999); - - Object.assign($params, {shippedFrom, shippedTo}); - } - - return $params; } } diff --git a/modules/travel/front/main/index.spec.js b/modules/travel/front/main/index.spec.js deleted file mode 100644 index bf5a27b41..000000000 --- a/modules/travel/front/main/index.spec.js +++ /dev/null @@ -1,49 +0,0 @@ -import './index.js'; - -describe('Travel Component vnTravel', () => { - let controller; - - beforeEach(ngModule('travel')); - - beforeEach(inject($componentController => { - let $element = angular.element(`
`); - controller = $componentController('vnTravel', {$element}); - })); - - describe('fetchParams()', () => { - it('should return a range of dates with passed scope days', () => { - let params = controller.fetchParams({ - scopeDays: 2 - }); - const shippedFrom = Date.vnNew(); - shippedFrom.setHours(0, 0, 0, 0); - const shippedTo = new Date(shippedFrom.getTime()); - shippedTo.setDate(shippedTo.getDate() + params.scopeDays); - shippedTo.setHours(23, 59, 59, 999); - - const expectedParams = { - shippedFrom, - scopeDays: params.scopeDays, - shippedTo - }; - - expect(params).toEqual(expectedParams); - }); - - it('should return default value for scope days', () => { - let params = controller.fetchParams({ - scopeDays: 1 - }); - - expect(params.scopeDays).toEqual(1); - }); - - it('should return the given scope days', () => { - let params = controller.fetchParams({ - scopeDays: 2 - }); - - expect(params.scopeDays).toEqual(2); - }); - }); -}); diff --git a/modules/travel/front/search-panel/index.html b/modules/travel/front/search-panel/index.html index 2e9c796c3..dd8d98af1 100644 --- a/modules/travel/front/search-panel/index.html +++ b/modules/travel/front/search-panel/index.html @@ -1,109 +1,146 @@ -
-
- - - - - - - - - - - - - - - - -
- - - - - - Or - - - - - -
- - - - - - - - - - - - - - - - - - - - -
\ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + Id/{{$ctrl.$t('Reference')}}: {{$ctrl.filter.search}} + + + {{$ctrl.$t('Agency')}}: {{agency.selection.name}} + + + {{$ctrl.$t('Warehouse Out')}}: {{warehouseOut.selection.name}} + + + {{$ctrl.$t('Warehouse In')}}: {{warehouseIn.selection.name}} + + + {{$ctrl.$t('Days onward')}}: {{$ctrl.filter.scopeDays}} + + + {{$ctrl.$t('Landed from')}}: {{$ctrl.filter.landedFrom | date:'dd/MM/yyyy'}} + + + {{$ctrl.$t('Landed to')}}: {{$ctrl.filter.landedTo | date:'dd/MM/yyyy'}} + + + {{$ctrl.$t('Continent Out')}}: {{continent.selection.name}} + + + {{$ctrl.$t('Total entries')}}: {{$ctrl.filter.totalEntries}} + +
+
diff --git a/modules/travel/front/search-panel/index.js b/modules/travel/front/search-panel/index.js index 877d4f9d3..9cf417da1 100644 --- a/modules/travel/front/search-panel/index.js +++ b/modules/travel/front/search-panel/index.js @@ -1,43 +1,69 @@ import ngModule from '../module'; import SearchPanel from 'core/components/searchbar/search-panel'; +import './style.scss'; class Controller extends SearchPanel { constructor($, $element) { super($, $element); - this.filter = this.$.filter; + this.initFilter(); + this.fetchData(); } - get shippedFrom() { - return this._shippedFrom; + $onChanges() { + if (this.model) + this.applyFilters(); } - set shippedFrom(value) { - this._shippedFrom = value; - this.filter.scopeDays = null; + fetchData() { + this.$http.get('AgencyModes').then(res => { + this.agencyModes = res.data; + }); + this.$http.get('Warehouses').then(res => { + this.warehouses = res.data; + }); + this.$http.get('Continents').then(res => { + this.continents = res.data; + }); } - get shippedTo() { - return this._shippedTo; + initFilter() { + this.filter = {}; + if (this.$params.q) { + this.filter = JSON.parse(this.$params.q); + this.search = this.filter.search; + this.totalEntries = this.filter.totalEntries; + } + if (!this.filter.scopeDays) this.filter.scopeDays = 7; } - set shippedTo(value) { - this._shippedTo = value; - this.filter.scopeDays = null; + applyFilters(param) { + this.model.applyFilter({}, this.filter) + .then(() => { + if (param && this.model._orgData.length === 1) + this.$state.go('travel.card.summary', {id: this.model._orgData[0].id}); + else + this.$state.go(this.$state.current.name, {q: JSON.stringify(this.filter)}, {location: 'replace'}); + }); } - get scopeDays() { - return this._scopeDays; + removeParamFilter(param) { + if (this[param]) delete this[param]; + delete this.filter[param]; + this.applyFilters(); } - set scopeDays(value) { - this._scopeDays = value; - - this.filter.shippedFrom = null; - this.filter.shippedTo = null; + onKeyPress($event, param) { + if ($event.key === 'Enter') { + this.filter[param] = this[param]; + this.applyFilters(param === 'search'); + } } } ngModule.vnComponent('vnTravelSearchPanel', { template: require('./index.html'), - controller: Controller + controller: Controller, + bindings: { + model: '<' + } }); diff --git a/modules/travel/front/search-panel/index.spec.js b/modules/travel/front/search-panel/index.spec.js index 884f4fb17..488143e80 100644 --- a/modules/travel/front/search-panel/index.spec.js +++ b/modules/travel/front/search-panel/index.spec.js @@ -8,41 +8,31 @@ describe('Travel Component vnTravelSearchPanel', () => { beforeEach(inject($componentController => { controller = $componentController('vnTravelSearchPanel', {$element: null}); controller.$t = () => {}; - controller.filter = {}; })); - describe('shippedFrom() setter', () => { - it('should clear the scope days when setting the from property', () => { - controller.filter.scopeDays = 1; + describe('applyFilters()', () => { + it('should apply filters', async() => { + controller.filter = {foo: 'bar'}; + controller.model = { + applyFilter: jest.fn().mockResolvedValue(), + _orgData: [{id: 1}] + }; + controller.$state = { + current: { + name: 'foo' + }, + go: jest.fn() + }; - controller.shippedFrom = Date.vnNew(); + await controller.applyFilters(true); - expect(controller.filter.scopeDays).toBeNull(); - expect(controller.shippedFrom).toBeDefined(); - }); - }); + expect(controller.model.applyFilter).toHaveBeenCalledWith({}, controller.filter); + expect(controller.$state.go).toHaveBeenCalledWith('travel.card.summary', {id: 1}); - describe('shippedTo() setter', () => { - it('should clear the scope days when setting the to property', () => { - controller.filter.scopeDays = 1; + await controller.applyFilters(false); - controller.shippedTo = Date.vnNew(); - - expect(controller.filter.scopeDays).toBeNull(); - expect(controller.shippedTo).toBeDefined(); - }); - }); - - describe('scopeDays() setter', () => { - it('should clear the date range when setting the scopeDays property', () => { - controller.filter.shippedFrom = Date.vnNew(); - controller.filter.shippedTo = Date.vnNew(); - - controller.scopeDays = 1; - - expect(controller.filter.shippedFrom).toBeNull(); - expect(controller.filter.shippedTo).toBeNull(); - expect(controller.scopeDays).toBeDefined(); + expect(controller.$state.go).toHaveBeenCalledWith(controller.$state.current.name, + {q: JSON.stringify(controller.filter)}, {location: 'replace'}); }); }); }); diff --git a/modules/travel/front/search-panel/style.scss b/modules/travel/front/search-panel/style.scss new file mode 100644 index 000000000..94fe7b239 --- /dev/null +++ b/modules/travel/front/search-panel/style.scss @@ -0,0 +1,37 @@ +@import "variables"; + +vn-travel-search-panel vn-side-menu { + .menu { + min-width: $right-menu-width; + } + & > div { + .input { + padding-left: $spacing-md; + padding-right: $spacing-md; + border-color: $color-spacer; + border-bottom: $border-thin; + } + .horizontal { + padding-left: $spacing-md; + padding-right: $spacing-md; + grid-auto-flow: column; + grid-column-gap: $spacing-sm; + align-items: center; + } + .chips { + display: flex; + flex-wrap: wrap; + padding: $spacing-md; + overflow: hidden; + max-width: 100%; + border-color: $color-spacer; + } + + .or { + align-self: center; + font-weight: bold; + font-size: 26px; + color: $color-font-secondary; + } + } +} diff --git a/modules/travel/front/summary/locale/es.yml b/modules/travel/front/summary/locale/es.yml index aa002fad0..aa6adc938 100644 --- a/modules/travel/front/summary/locale/es.yml +++ b/modules/travel/front/summary/locale/es.yml @@ -1,9 +1,9 @@ Reference: Referencia -Warehouse In: Almacén entrada -Warehouse Out: Almacén salida +Warehouse In: Alm. entrada +Warehouse Out: Alm. salida Shipped: F. envío Landed: F. entrega -Total entries: Entradas totales +Total entries: Ent. totales Delivered: Enviada Received: Recibida Agency: Agencia diff --git a/modules/wagon/back/methods/wagonType/createWagonType.js b/modules/wagon/back/methods/wagonType/createWagonType.js new file mode 100644 index 000000000..fed915b28 --- /dev/null +++ b/modules/wagon/back/methods/wagonType/createWagonType.js @@ -0,0 +1,57 @@ +module.exports = Self => { + Self.remoteMethodCtx('createWagonType', { + description: 'Creates a new wagon type', + accessType: 'WRITE', + accepts: [ + { + arg: 'name', + type: 'String', + required: true + }, + { + arg: 'divisible', + type: 'boolean', + required: true + }, { + arg: 'trays', + type: 'any', + required: true + } + ], + http: { + path: `/createWagonType`, + verb: 'PATCH' + } + }); + + Self.createWagonType = async(ctx, options) => { + const args = ctx.args; + const models = Self.app.models; + const myOptions = {}; + let tx; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + if (!myOptions.transaction) { + tx = await Self.beginTransaction({}); + myOptions.transaction = tx; + } + + try { + const newWagonType = await models.WagonType.create({name: args.name, divisible: args.divisible}, myOptions); + args.trays.forEach(async tray => { + await models.WagonTypeTray.create({ + typeFk: newWagonType.id, + height: tray.position, + colorFk: tray.color.id + }, myOptions); + }); + + if (tx) await tx.commit(); + } catch (e) { + if (tx) await tx.rollback(); + throw e; + } + }; +}; diff --git a/modules/wagon/back/methods/wagonType/deleteWagonType.js b/modules/wagon/back/methods/wagonType/deleteWagonType.js new file mode 100644 index 000000000..46b65e32f --- /dev/null +++ b/modules/wagon/back/methods/wagonType/deleteWagonType.js @@ -0,0 +1,43 @@ +module.exports = Self => { + Self.remoteMethodCtx('deleteWagonType', { + description: 'Deletes a wagon type', + accessType: 'WRITE', + accepts: [ + { + arg: 'id', + type: 'Number', + required: true + } + ], + http: { + path: `/deleteWagonType`, + verb: 'DELETE' + } + }); + + Self.deleteWagonType = async(ctx, options) => { + const args = ctx.args; + const models = Self.app.models; + const myOptions = {}; + let tx; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + if (!myOptions.transaction) { + tx = await Self.beginTransaction({}); + myOptions.transaction = tx; + } + + try { + await models.Wagon.destroyAll({typeFk: args.id}, myOptions); + await models.WagonTypeTray.destroyAll({typeFk: args.id}, myOptions); + await models.WagonType.destroyAll({id: args.id}, myOptions); + + if (tx) await tx.commit(); + } catch (e) { + if (tx) await tx.rollback(); + throw e; + } + }; +}; diff --git a/modules/wagon/back/methods/wagonType/editWagonType.js b/modules/wagon/back/methods/wagonType/editWagonType.js new file mode 100644 index 000000000..bd5ad1f16 --- /dev/null +++ b/modules/wagon/back/methods/wagonType/editWagonType.js @@ -0,0 +1,64 @@ +module.exports = Self => { + Self.remoteMethodCtx('editWagonType', { + description: 'Edits a new wagon type', + accessType: 'WRITE', + accepts: [ + { + arg: 'id', + type: 'String', + required: true + }, + { + arg: 'name', + type: 'String', + required: true + }, + { + arg: 'divisible', + type: 'boolean', + required: true + }, { + arg: 'trays', + type: 'any', + required: true + } + ], + http: { + path: `/editWagonType`, + verb: 'PATCH' + } + }); + + Self.editWagonType = async(ctx, options) => { + const args = ctx.args; + const models = Self.app.models; + const myOptions = {}; + let tx; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + if (!myOptions.transaction) { + tx = await Self.beginTransaction({}); + myOptions.transaction = tx; + } + + try { + const wagonType = await models.WagonType.findById(args.id, null, myOptions); + wagonType.updateAttributes({name: args.name, divisible: args.divisible}, myOptions); + models.WagonTypeTray.destroyAll({typeFk: args.id}, myOptions); + args.trays.forEach(async tray => { + await models.WagonTypeTray.create({ + typeFk: args.id, + height: tray.position, + colorFk: tray.color.id + }, myOptions); + }); + + if (tx) await tx.commit(); + } catch (e) { + if (tx) await tx.rollback(); + throw e; + } + }; +}; diff --git a/modules/wagon/back/methods/wagonType/specs/crudWagonType.spec.js b/modules/wagon/back/methods/wagonType/specs/crudWagonType.spec.js new file mode 100644 index 000000000..92ac61060 --- /dev/null +++ b/modules/wagon/back/methods/wagonType/specs/crudWagonType.spec.js @@ -0,0 +1,63 @@ +const models = require('vn-loopback/server/server').models; + +describe('WagonType crudWagonType()', () => { + const ctx = { + args: { + name: 'Mock wagon type', + divisible: true, + trays: [{position: 0, color: {id: 1}}, + {position: 50, color: {id: 2}}, + {position: 100, color: {id: 3}}] + } + }; + + it(`should create, edit and delete a new wagon type and its trays`, async() => { + const tx = await models.WagonType.beginTransaction({}); + + try { + const options = {transaction: tx}; + + // create + await models.WagonType.createWagonType(ctx, options); + + const newWagonType = await models.WagonType.findOne({where: {name: ctx.args.name}}, options); + const newWagonTrays = await models.WagonTypeTray.find({where: {typeFk: newWagonType.id}}, options); + + expect(newWagonType).not.toEqual(null); + expect(newWagonType.name).toEqual(ctx.args.name); + expect(newWagonType.divisible).toEqual(ctx.args.divisible); + expect(newWagonTrays.length).toEqual(ctx.args.trays.length); + + ctx.args = { + id: newWagonType.id, + name: 'Edited wagon type', + divisible: false, + trays: [{position: 0, color: {id: 1}}] + }; + + // edit + await models.WagonType.editWagonType(ctx, options); + + const editedWagonType = await models.WagonType.findById(newWagonType.id, null, options); + const editedWagonTrays = await models.WagonTypeTray.find({where: {typeFk: newWagonType.id}}, options); + + expect(editedWagonType.name).toEqual(ctx.args.name); + expect(editedWagonType.divisible).toEqual(ctx.args.divisible); + expect(editedWagonTrays.length).toEqual(ctx.args.trays.length); + + // delete + await models.WagonType.deleteWagonType(ctx, options); + + const deletedWagonType = await models.WagonType.findById(newWagonType.id, null, options); + const deletedWagonTrays = await models.WagonTypeTray.find({where: {typeFk: newWagonType.id}}, options); + + expect(deletedWagonType).toEqual(null); + expect(deletedWagonTrays).toEqual([]); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); +}); diff --git a/modules/wagon/back/model-config.json b/modules/wagon/back/model-config.json new file mode 100644 index 000000000..279d55e5c --- /dev/null +++ b/modules/wagon/back/model-config.json @@ -0,0 +1,23 @@ +{ + "Wagon": { + "dataSource": "vn" + }, + "WagonType": { + "dataSource": "vn" + }, + "WagonTypeColor": { + "dataSource": "vn" + }, + "WagonTypeTray": { + "dataSource": "vn" + }, + "WagonConfig": { + "dataSource": "vn" + }, + "CollectionWagon": { + "dataSource": "vn" + }, + "CollectionWagonTicket": { + "dataSource": "vn" + } +} diff --git a/modules/wagon/back/models/collection-wagon-ticket.json b/modules/wagon/back/models/collection-wagon-ticket.json new file mode 100644 index 000000000..04527205c --- /dev/null +++ b/modules/wagon/back/models/collection-wagon-ticket.json @@ -0,0 +1,43 @@ +{ + "name": "CollectionWagonTicket", + "base": "VnModel", + "options": { + "mysql": { + "table": "collectionWagonTicket" + } + }, + "properties": { + "ticketFk": { + "id": true, + "type": "number" + }, + "wagonFk": { + "type": "number", + "required": true + }, + "trayFk": { + "type": "number", + "required": true + }, + "side": { + "type": "string" + } + }, + "relations": { + "ticket": { + "type": "belongsTo", + "model": "Ticket", + "foreignKey": "ticketFk" + }, + "wagon": { + "type": "belongsTo", + "model": "Wagon", + "foreignKey": "wagonFk" + }, + "tray": { + "type": "belongsTo", + "model": "WagonTypeTray", + "foreignKey": "trayFk" + } + } +} diff --git a/modules/wagon/back/models/collection-wagon.json b/modules/wagon/back/models/collection-wagon.json new file mode 100644 index 000000000..f3f237428 --- /dev/null +++ b/modules/wagon/back/models/collection-wagon.json @@ -0,0 +1,34 @@ +{ + "name": "CollectionWagon", + "base": "VnModel", + "options": { + "mysql": { + "table": "collectionWagon" + } + }, + "properties": { + "collectionFk": { + "id": true, + "type": "number" + }, + "wagonFk": { + "type": "number", + "required": true + }, + "position": { + "type": "number" + } + }, + "relations": { + "collection": { + "type": "belongsTo", + "model": "Collection", + "foreignKey": "collectionFk" + }, + "wagon": { + "type": "belongsTo", + "model": "Wagon", + "foreignKey": "wagonFk" + } + } +} diff --git a/modules/wagon/back/models/wagon-config.json b/modules/wagon/back/models/wagon-config.json new file mode 100644 index 000000000..3d96e2864 --- /dev/null +++ b/modules/wagon/back/models/wagon-config.json @@ -0,0 +1,30 @@ +{ + "name": "WagonConfig", + "base": "VnModel", + "options": { + "mysql": { + "table": "wagonConfig" + } + }, + "properties": { + "id": { + "id": true, + "type": "number" + }, + "width": { + "type": "number" + }, + "height": { + "type": "string" + }, + "maxWagonHeight": { + "type": "number" + }, + "minHeightBetweenTrays": { + "type": "number" + }, + "maxTrays": { + "type": "number" + } + } +} diff --git a/modules/wagon/back/models/wagon-type-color.json b/modules/wagon/back/models/wagon-type-color.json new file mode 100644 index 000000000..573fd60f5 --- /dev/null +++ b/modules/wagon/back/models/wagon-type-color.json @@ -0,0 +1,21 @@ +{ + "name": "WagonTypeColor", + "base": "VnModel", + "options": { + "mysql": { + "table": "wagonTypeColor" + } + }, + "properties": { + "id": { + "id": true, + "type": "number" + }, + "name": { + "type": "string" + }, + "rgb": { + "type": "string" + } + } +} diff --git a/modules/wagon/back/models/wagon-type-tray.json b/modules/wagon/back/models/wagon-type-tray.json new file mode 100644 index 000000000..b61510bcf --- /dev/null +++ b/modules/wagon/back/models/wagon-type-tray.json @@ -0,0 +1,36 @@ +{ + "name": "WagonTypeTray", + "base": "VnModel", + "options": { + "mysql": { + "table": "wagonTypeTray" + } + }, + "properties": { + "id": { + "id": true, + "type": "number" + }, + "typeFk": { + "type": "number" + }, + "height": { + "type": "number" + }, + "colorFk": { + "type": "number" + } + }, + "relations": { + "type": { + "type": "belongsTo", + "model": "WagonType", + "foreignKey": "typeFk" + }, + "color": { + "type": "belongsTo", + "model": "WagonTypeColor", + "foreignKey": "colorFk" + } + } +} diff --git a/modules/wagon/back/models/wagon-type.js b/modules/wagon/back/models/wagon-type.js new file mode 100644 index 000000000..bebf7a9d9 --- /dev/null +++ b/modules/wagon/back/models/wagon-type.js @@ -0,0 +1,5 @@ +module.exports = Self => { + require('../methods/wagonType/createWagonType')(Self); + require('../methods/wagonType/editWagonType')(Self); + require('../methods/wagonType/deleteWagonType')(Self); +}; diff --git a/modules/wagon/back/models/wagon-type.json b/modules/wagon/back/models/wagon-type.json new file mode 100644 index 000000000..f57bf957d --- /dev/null +++ b/modules/wagon/back/models/wagon-type.json @@ -0,0 +1,21 @@ +{ + "name": "WagonType", + "base": "VnModel", + "options": { + "mysql": { + "table": "wagonType" + } + }, + "properties": { + "id": { + "id": true, + "type": "number" + }, + "name": { + "type": "string" + }, + "divisible": { + "type": "boolean" + } + } +} diff --git a/modules/wagon/back/models/wagon.json b/modules/wagon/back/models/wagon.json new file mode 100644 index 000000000..61ee61e61 --- /dev/null +++ b/modules/wagon/back/models/wagon.json @@ -0,0 +1,34 @@ +{ + "name": "Wagon", + "base": "VnModel", + "options": { + "mysql": { + "table": "wagon" + } + }, + "properties": { + "id": { + "id": true, + "type": "number" + }, + "label": { + "type": "number" + }, + "volume": { + "type": "number" + }, + "plate": { + "type": "string" + }, + "typeFk": { + "type": "number" + } + }, + "relations": { + "type": { + "type": "belongsTo", + "model": "WagonType", + "foreignKey": "typeFk" + } + } +} diff --git a/modules/worker/back/methods/worker-time-control/addTimeEntry.js b/modules/worker/back/methods/worker-time-control/addTimeEntry.js index fef3cf223..c8c08d9b1 100644 --- a/modules/worker/back/methods/worker-time-control/addTimeEntry.js +++ b/modules/worker/back/methods/worker-time-control/addTimeEntry.js @@ -51,6 +51,8 @@ module.exports = Self => { if (response[0] && response[0].error) throw new UserError(response[0].error); + await models.WorkerTimeControl.resendWeeklyHourEmail(ctx, workerId, args.timed, myOptions); + return response; }; }; diff --git a/modules/worker/back/methods/worker-time-control/deleteTimeEntry.js b/modules/worker/back/methods/worker-time-control/deleteTimeEntry.js index c80dcab81..e33d6b790 100644 --- a/modules/worker/back/methods/worker-time-control/deleteTimeEntry.js +++ b/modules/worker/back/methods/worker-time-control/deleteTimeEntry.js @@ -38,7 +38,11 @@ module.exports = Self => { if (isSubordinate === false || (isSubordinate && isHimself && !isTeamBoss)) throw new UserError(`You don't have enough privileges`); - return Self.rawSql('CALL vn.workerTimeControl_remove(?, ?)', [ + const response = await Self.rawSql('CALL vn.workerTimeControl_remove(?, ?)', [ targetTimeEntry.userFk, targetTimeEntry.timed], myOptions); + + await models.WorkerTimeControl.resendWeeklyHourEmail(ctx, targetTimeEntry.userFk, targetTimeEntry.timed, myOptions); + + return response; }; }; diff --git a/modules/worker/back/methods/worker-time-control/getMailStates.js b/modules/worker/back/methods/worker-time-control/getMailStates.js new file mode 100644 index 000000000..855b5adc3 --- /dev/null +++ b/modules/worker/back/methods/worker-time-control/getMailStates.js @@ -0,0 +1,61 @@ +module.exports = Self => { + Self.remoteMethodCtx('getMailStates', { + description: 'Get the states of a month about time control mail', + accessType: 'READ', + accepts: [{ + arg: 'id', + type: 'number', + description: 'The worker id', + http: {source: 'path'} + }, + { + arg: 'month', + type: 'number', + description: 'The number of the month' + }, + { + arg: 'year', + type: 'number', + description: 'The number of the year' + }], + returns: [{ + type: ['object'], + root: true + }], + http: { + path: `/:id/getMailStates`, + verb: 'GET' + } + }); + + Self.getMailStates = async(ctx, workerId, options) => { + const models = Self.app.models; + const args = ctx.args; + const myOptions = {}; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + const times = await models.Time.find({ + fields: ['week'], + where: { + month: args.month, + year: args.year + } + }, myOptions); + + const weeks = times.map(time => time.week); + const weekNumbersSet = new Set(weeks); + const weekNumbers = Array.from(weekNumbersSet); + + const workerTimeControlMails = await models.WorkerTimeControlMail.find({ + where: { + workerFk: workerId, + year: args.year, + week: {inq: weekNumbers} + } + }, myOptions); + + return workerTimeControlMails; + }; +}; diff --git a/modules/worker/back/methods/worker-time-control/resendWeeklyHourEmail.js b/modules/worker/back/methods/worker-time-control/resendWeeklyHourEmail.js new file mode 100644 index 000000000..2452a29f9 --- /dev/null +++ b/modules/worker/back/methods/worker-time-control/resendWeeklyHourEmail.js @@ -0,0 +1,68 @@ +module.exports = Self => { + Self.remoteMethodCtx('resendWeeklyHourEmail', { + description: 'Adds a new hour registry', + accessType: 'WRITE', + accepts: [{ + arg: 'id', + type: 'number', + description: 'The worker id', + http: {source: 'path'} + }, + { + arg: 'dated', + type: 'date', + required: true + }], + returns: [{ + type: 'Object', + root: true + }], + http: { + path: `/:id/resendWeeklyHourEmail`, + verb: 'POST' + } + }); + + Self.resendWeeklyHourEmail = async(ctx, workerId, dated, options) => { + const models = Self.app.models; + const myOptions = {}; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + const yearNumber = dated.getFullYear(); + const weekNumber = getWeekNumber(dated); + const workerTimeControlMail = await models.WorkerTimeControlMail.findOne({ + where: { + workerFk: workerId, + year: yearNumber, + week: weekNumber + } + }, myOptions); + + if (workerTimeControlMail && workerTimeControlMail.state != 'SENDED') { + const worker = await models.EmailUser.findById(workerId, null, myOptions); + ctx.args = { + recipient: worker.email, + year: yearNumber, + week: weekNumber, + workerId: workerId, + state: 'SENDED' + }; + return models.WorkerTimeControl.weeklyHourRecordEmail(ctx, myOptions); + } + + return false; + }; + + function getWeekNumber(date) { + const tempDate = new Date(date); + let dayOfWeek = tempDate.getDay(); + dayOfWeek = (dayOfWeek === 0) ? 7 : dayOfWeek; + const firstDayOfWeek = new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate() - (dayOfWeek - 1)); + const firstDayOfYear = new Date(tempDate.getFullYear(), 0, 1); + const differenceInMilliseconds = firstDayOfWeek.getTime() - firstDayOfYear.getTime(); + const weekNumber = Math.floor(differenceInMilliseconds / (1000 * 60 * 60 * 24 * 7)) + 1; + return weekNumber; + } +}; diff --git a/modules/worker/back/methods/worker-time-control/sendMail.js b/modules/worker/back/methods/worker-time-control/sendMail.js index 579a83112..2c827e320 100644 --- a/modules/worker/back/methods/worker-time-control/sendMail.js +++ b/modules/worker/back/methods/worker-time-control/sendMail.js @@ -82,14 +82,9 @@ module.exports = Self => { updated: Date.vnNew(), state: 'SENDED' }, myOptions); - stmt = new ParameterizedSQL( - `CALL vn.timeControl_calculateByUser(?, ?, ?) - `, [args.workerId, started, ended]); + stmt = new ParameterizedSQL('DROP TEMPORARY TABLE IF EXISTS tmp.`user`'); stmts.push(stmt); - - stmt = new ParameterizedSQL( - `CALL vn.timeBusiness_calculateByUser(?, ?, ?) - `, [args.workerId, started, ended]); + stmt = new ParameterizedSQL('CREATE TEMPORARY TABLE tmp.`user` SELECT id userFk FROM account.user WHERE id = ?', [args.workerId]); stmts.push(stmt); } else { await models.WorkerTimeControl.destroyAll({ @@ -105,13 +100,38 @@ module.exports = Self => { updated: Date.vnNew(), state: 'SENDED' }, myOptions); - stmt = new ParameterizedSQL(`CALL vn.timeControl_calculateAll(?, ?)`, [started, ended]); + stmt = new ParameterizedSQL('DROP TEMPORARY TABLE IF EXISTS tmp.`user`'); stmts.push(stmt); - - stmt = new ParameterizedSQL(`CALL vn.timeBusiness_calculateAll(?, ?)`, [started, ended]); + stmt = new ParameterizedSQL('CREATE TEMPORARY TABLE IF NOT EXISTS tmp.`user` SELECT userFk FROM vn.worker w JOIN account.`user` u ON u.id = w.userFk WHERE userFk IS NOT NULL'); stmts.push(stmt); } + stmt = new ParameterizedSQL( + `CALL vn.timeControl_calculate(?, ?) + `, [started, ended]); + stmts.push(stmt); + + stmt = new ParameterizedSQL( + `CALL vn.timeBusiness_calculate(?, ?) + `, [started, ended]); + stmts.push(stmt); + + stmt = new ParameterizedSQL( + `CALL vn.timeControl_getError(?, ?) + `, [started, ended]); + stmts.push(stmt); + + stmt = new ParameterizedSQL(`INSERT INTO mail (receiver, subject, body) + SELECT CONCAT(u.name, '@verdnatura.es'), + CONCAT('Error registro de horas semana ', ?, ' año ', ?) , + CONCAT('No se ha podido enviar el registro de horas al empleado/s: ', GROUP_CONCAT(DISTINCT CONCAT('
', w.id, ' ', w.firstName, ' ', w.lastName))) + FROM tmp.timeControlError tce + JOIN vn.workerTimeControl wtc ON wtc.id = tce.id + JOIN worker w ON w.id = wtc.userFK + JOIN account.user u ON u.id = w.bossFk + GROUP BY w.bossFk`, [args.week, args.year]); + stmts.push(stmt); + stmt = new ParameterizedSQL(` SELECT CONCAT(u.name, '@verdnatura.es') receiver, u.id workerFk, @@ -131,20 +151,16 @@ module.exports = Self => { JOIN business b ON b.id = tb.businessFk LEFT JOIN tmp.timeControlCalculate tc ON tc.userFk = tb.userFk AND tc.dated = tb.dated LEFT JOIN worker w ON w.id = u.id - JOIN (SELECT tb.userFk, - SUM(IF(tb.type IS NULL, - IF(tc.timeWorkDecimal > 0, FALSE, IF(tb.timeWorkDecimal > 0, TRUE, FALSE)), - TRUE))isTeleworkingWeek - FROM tmp.timeBusinessCalculate tb - LEFT JOIN tmp.timeControlCalculate tc ON tc.userFk = tb.userFk - AND tc.dated = tb.dated - GROUP BY tb.userFk - HAVING isTeleworkingWeek > 0 - )sub ON sub.userFk = u.id - WHERE d.hasToRefill + LEFT JOIN ( + SELECT DISTINCT wtc.userFk + FROM tmp.timeControlError tce + JOIN vn.workerTimeControl wtc ON wtc.id = tce.id + )sub ON sub.userFk = tb.userFk + WHERE sub.userFK IS NULL AND IFNULL(?, u.id) = u.id AND b.companyCodeFk = 'VNL' AND w.businessFk + AND d.isTeleworking ORDER BY u.id, tb.dated `, [args.workerId]); const index = stmts.push(stmt) - 1; @@ -332,17 +348,18 @@ module.exports = Self => { const lastDay = days[index][days[index].length - 1]; if (day.workerFk != previousWorkerFk || day == lastDay) { - const salix = await models.Url.findOne({ - where: { - appName: 'salix', - environment: process.env.NODE_ENV || 'dev' - } - }, myOptions); + const query = `INSERT IGNORE INTO workerTimeControlMail (workerFk, year, week) + VALUES(?, ?, ?);`; + await Self.rawSql(query, [previousWorkerFk, args.year, args.week]); - const timestamp = started.getTime() / 1000; - const url = `${salix.url}worker/${previousWorkerFk}/time-control?timestamp=${timestamp}`; - - await models.WorkerTimeControl.weeklyHourRecordEmail(ctx, previousReceiver, args.week, args.year, url); + ctx.args = { + recipient: previousReceiver, + year: args.year, + week: args.week, + workerId: previousWorkerFk, + state: 'SENDED' + }; + await models.WorkerTimeControl.weeklyHourRecordEmail(ctx, myOptions); previousWorkerFk = day.workerFk; previousReceiver = day.receiver; diff --git a/modules/worker/back/methods/worker-time-control/specs/getMailStates.spec.js b/modules/worker/back/methods/worker-time-control/specs/getMailStates.spec.js new file mode 100644 index 000000000..cbad32323 --- /dev/null +++ b/modules/worker/back/methods/worker-time-control/specs/getMailStates.spec.js @@ -0,0 +1,29 @@ +const models = require('vn-loopback/server/server').models; + +describe('workerTimeControl getMailStates()', () => { + const workerId = 9; + const ctx = {args: { + month: 12, + year: 2000 + }}; + + it('should get the states of a month about time control mail', async() => { + const tx = await models.WorkerTimeControl.beginTransaction({}); + + try { + const options = {transaction: tx}; + + const response = await models.WorkerTimeControl.getMailStates(ctx, workerId, options); + + expect(response[0].state).toEqual('REVISE'); + expect(response[1].state).toEqual('SENDED'); + expect(response[2].state).toEqual('CONFIRMED'); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); +}); + diff --git a/modules/worker/back/methods/worker-time-control/specs/sendMail.spec.js b/modules/worker/back/methods/worker-time-control/specs/sendMail.spec.js deleted file mode 100644 index 24bfd6904..000000000 --- a/modules/worker/back/methods/worker-time-control/specs/sendMail.spec.js +++ /dev/null @@ -1,120 +0,0 @@ -const models = require('vn-loopback/server/server').models; - -describe('workerTimeControl sendMail()', () => { - const workerId = 18; - const activeCtx = { - getLocale: () => { - return 'en'; - } - }; - const ctx = {req: activeCtx, args: {}}; - - it('should fill time control of a worker without records in Journey and with rest', async() => { - const tx = await models.WorkerTimeControl.beginTransaction({}); - - try { - const options = {transaction: tx}; - - await models.WorkerTimeControl.sendMail(ctx, options); - - const workerTimeControl = await models.WorkerTimeControl.find({ - where: {userFk: workerId} - }, options); - - expect(workerTimeControl[0].timed.getHours()).toEqual(8); - expect(workerTimeControl[1].timed.getHours()).toEqual(9); - expect(`${workerTimeControl[2].timed.getHours()}:${workerTimeControl[2].timed.getMinutes()}`).toEqual('9:20'); - expect(workerTimeControl[3].timed.getHours()).toEqual(16); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - throw e; - } - }); - - it('should fill time control of a worker without records in Journey and without rest', async() => { - const workdayOf20Hours = 3; - const tx = await models.WorkerTimeControl.beginTransaction({}); - - try { - const options = {transaction: tx}; - query = `UPDATE business b - SET b.calendarTypeFk = ? - WHERE b.workerFk = ?; `; - await models.WorkerTimeControl.rawSql(query, [workdayOf20Hours, workerId], options); - - await models.WorkerTimeControl.sendMail(ctx, options); - - const workerTimeControl = await models.WorkerTimeControl.find({ - where: {userFk: workerId} - }, options); - - expect(workerTimeControl[0].timed.getHours()).toEqual(8); - expect(workerTimeControl[1].timed.getHours()).toEqual(12); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - throw e; - } - }); - - it('should fill time control of a worker with records in Journey and with rest', async() => { - const tx = await models.WorkerTimeControl.beginTransaction({}); - - try { - const options = {transaction: tx}; - query = `INSERT INTO postgresql.journey(journey_id, day_id, start, end, business_id) - VALUES - (1, 1, '09:00:00', '13:00:00', ?), - (2, 1, '14:00:00', '19:00:00', ?);`; - await models.WorkerTimeControl.rawSql(query, [workerId, workerId, workerId], options); - - await models.WorkerTimeControl.sendMail(ctx, options); - - const workerTimeControl = await models.WorkerTimeControl.find({ - where: {userFk: workerId} - }, options); - - expect(workerTimeControl[0].timed.getHours()).toEqual(9); - expect(workerTimeControl[2].timed.getHours()).toEqual(10); - expect(`${workerTimeControl[3].timed.getHours()}:${workerTimeControl[3].timed.getMinutes()}`).toEqual('10:20'); - expect(workerTimeControl[1].timed.getHours()).toEqual(13); - expect(workerTimeControl[4].timed.getHours()).toEqual(14); - expect(workerTimeControl[5].timed.getHours()).toEqual(19); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - throw e; - } - }); - - it('should fill time control of a worker with records in Journey and without rest', async() => { - const tx = await models.WorkerTimeControl.beginTransaction({}); - - try { - const options = {transaction: tx}; - query = `INSERT INTO postgresql.journey(journey_id, day_id, start, end, business_id) - VALUES - (1, 1, '12:30:00', '14:00:00', ?);`; - await models.WorkerTimeControl.rawSql(query, [workerId, workerId, workerId], options); - - await models.WorkerTimeControl.sendMail(ctx, options); - - const workerTimeControl = await models.WorkerTimeControl.find({ - where: {userFk: workerId} - }, options); - - expect(`${workerTimeControl[0].timed.getHours()}:${workerTimeControl[0].timed.getMinutes()}`).toEqual('12:30'); - expect(workerTimeControl[1].timed.getHours()).toEqual(14); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - throw e; - } - }); -}); - diff --git a/modules/worker/back/methods/worker-time-control/updateTimeEntry.js b/modules/worker/back/methods/worker-time-control/updateTimeEntry.js index a99a61770..83349ea63 100644 --- a/modules/worker/back/methods/worker-time-control/updateTimeEntry.js +++ b/modules/worker/back/methods/worker-time-control/updateTimeEntry.js @@ -46,8 +46,12 @@ module.exports = Self => { if (notAllowed) throw new UserError(`You don't have enough privileges`); - return targetTimeEntry.updateAttributes({ + const timeEntryUpdated = await targetTimeEntry.updateAttributes({ direction: args.direction }, myOptions); + + await models.WorkerTimeControl.resendWeeklyHourEmail(ctx, targetTimeEntry.userFk, targetTimeEntry.timed, myOptions); + + return timeEntryUpdated; }; }; diff --git a/modules/worker/back/methods/worker-time-control/updateWorkerTimeControlMail.js b/modules/worker/back/methods/worker-time-control/updateWorkerTimeControlMail.js index a8dc14bb1..6f794511f 100644 --- a/modules/worker/back/methods/worker-time-control/updateWorkerTimeControlMail.js +++ b/modules/worker/back/methods/worker-time-control/updateWorkerTimeControlMail.js @@ -60,13 +60,17 @@ module.exports = Self => { const oldState = workerTimeControlMail.state; const oldReason = workerTimeControlMail.reason; - if (oldState == args.state) throw new UserError('Already has this status'); - await workerTimeControlMail.updateAttributes({ state: args.state, reason: args.reason || null }, myOptions); + if (args.state == 'SENDED') { + await workerTimeControlMail.updateAttributes({ + sendedCounter: workerTimeControlMail.sendedCounter + 1 + }, myOptions); + } + const logRecord = { originFk: args.workerId, userFk: userId, diff --git a/modules/worker/back/methods/worker-time-control/weeklyHourRecordEmail.js b/modules/worker/back/methods/worker-time-control/weeklyHourRecordEmail.js index 6feadb936..f44080559 100644 --- a/modules/worker/back/methods/worker-time-control/weeklyHourRecordEmail.js +++ b/modules/worker/back/methods/worker-time-control/weeklyHourRecordEmail.js @@ -1,5 +1,3 @@ -const {Email} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('weeklyHourRecordEmail', { description: 'Sends the weekly hour record', @@ -22,7 +20,12 @@ module.exports = Self => { required: true }, { - arg: 'url', + arg: 'workerId', + type: 'number', + required: true + }, + { + arg: 'state', type: 'string', required: true } @@ -37,17 +40,48 @@ module.exports = Self => { } }); - Self.weeklyHourRecordEmail = async(ctx, recipient, week, year, url) => { - const params = { - recipient: recipient, - lang: ctx.req.getLocale(), - week: week, - year: year, - url: url - }; + Self.weeklyHourRecordEmail = async(ctx, options) => { + const models = Self.app.models; + const args = ctx.args; + const myOptions = {}; - const email = new Email('weekly-hour-record', params); + if (typeof options == 'object') + Object.assign(myOptions, options); - return email.send(); + const salix = await models.Url.findOne({ + where: { + appName: 'salix', + environment: process.env.NODE_ENV || 'dev' + } + }, myOptions); + + const dated = getMondayDateFromYearWeek(args.year, args.week); + const timestamp = dated.getTime() / 1000; + + const url = `${salix.url}worker/${args.workerId}/time-control?timestamp=${timestamp}`; + ctx.args.url = url; + + Self.sendTemplate(ctx, 'weekly-hour-record'); + + return models.WorkerTimeControl.updateWorkerTimeControlMail(ctx, myOptions); }; + + function getMondayDateFromYearWeek(yearNumber, weekNumber) { + const yearStart = new Date(yearNumber, 0, 1); + const firstMonday = new Date(yearStart.getTime() + ((7 - yearStart.getDay() + 1) % 7) * 86400000); + const firstMondayWeekNumber = getWeekNumber(firstMonday); + + if (firstMondayWeekNumber > 1) + firstMonday.setDate(firstMonday.getDate() + 7); + + firstMonday.setDate(firstMonday.getDate() + (weekNumber - 1) * 7); + + return firstMonday; + } + + function getWeekNumber(date) { + const firstDayOfYear = new Date(date.getFullYear(), 0, 1); + const daysPassed = (date - firstDayOfYear) / 86400000; + return Math.ceil((daysPassed + firstDayOfYear.getDay() + 1) / 7); + } }; diff --git a/modules/worker/back/model-config.json b/modules/worker/back/model-config.json index 8079bd165..145934700 100644 --- a/modules/worker/back/model-config.json +++ b/modules/worker/back/model-config.json @@ -53,6 +53,9 @@ "Worker": { "dataSource": "vn" }, + "WorkerObservation": { + "dataSource": "vn" + }, "WorkerConfig": { "dataSource": "vn" }, @@ -94,6 +97,9 @@ }, "WorkerTimeControlMail": { "dataSource": "vn" + }, + "Operator": { + "dataSource": "vn" } } diff --git a/modules/worker/back/models/operator.json b/modules/worker/back/models/operator.json new file mode 100644 index 000000000..db8a8c451 --- /dev/null +++ b/modules/worker/back/models/operator.json @@ -0,0 +1,44 @@ +{ + "name": "Operator", + "base": "VnModel", + "options": { + "mysql": { + "table": "operator" + } + }, + "properties": { + "workerFk": { + "id": true, + "type": "number", + "required": true + }, + "numberOfWagons": { + "type": "number" + }, + "trainFk": { + "type": "number", + "required": true + }, + "itemPackingTypeFk": { + "type": "string", + "required": true + }, + "warehouseFk": { + "type": "number", + "required": true + }, + "sectorFk ": { + "type": "number" + }, + "labelerFk ": { + "type": "number" + } + }, + "relations": { + "sector": { + "type": "belongsTo", + "model": "Sector", + "foreignKey": "sectorFk" + } + } +} \ No newline at end of file diff --git a/modules/worker/back/models/time.json b/modules/worker/back/models/time.json index df9257540..e2f1161d7 100644 --- a/modules/worker/back/models/time.json +++ b/modules/worker/back/models/time.json @@ -14,6 +14,9 @@ "year": { "type": "number" }, + "month": { + "type": "number" + }, "week": { "type": "number" } diff --git a/modules/worker/back/models/worker-dms.json b/modules/worker/back/models/worker-dms.json index 575cfbc24..e9a9f1773 100644 --- a/modules/worker/back/models/worker-dms.json +++ b/modules/worker/back/models/worker-dms.json @@ -1,11 +1,6 @@ { "name": "WorkerDms", "base": "Loggable", - "log": { - "model":"ClientLog", - "relation": "worker", - "showField": "dmsFk" - }, "options": { "mysql": { "table": "workerDocument" diff --git a/modules/worker/back/models/worker-observation.js b/modules/worker/back/models/worker-observation.js new file mode 100644 index 000000000..cccc2cfbd --- /dev/null +++ b/modules/worker/back/models/worker-observation.js @@ -0,0 +1,12 @@ +module.exports = function(Self) { + Self.validatesPresenceOf('text', { + message: 'Description cannot be blank' + }); + + Self.observe('before save', async function(ctx) { + ctx.instance.created = new Date(); + let token = ctx.options.accessToken; + let userId = token && token.userId; + ctx.instance.userFk = userId; + }); +}; diff --git a/modules/worker/back/models/worker-observation.json b/modules/worker/back/models/worker-observation.json new file mode 100644 index 000000000..90eb35837 --- /dev/null +++ b/modules/worker/back/models/worker-observation.json @@ -0,0 +1,39 @@ +{ + "name": "WorkerObservation", + "base": "VnModel", + "options": { + "mysql": { + "table": "workerObservation" + } + }, + "properties": { + "id": { + "id": true, + "type": "number" + }, + "workerFk": { + "type": "number" + }, + "userFk": { + "type": "number" + }, + "text": { + "type": "string" + }, + "created": { + "type": "date" + } + }, + "relations": { + "worker": { + "type": "belongsTo", + "model": "Worker", + "foreignKey": "workerFk" + }, + "user":{ + "type": "belongsTo", + "model": "Account", + "foreignKey": "userFk" + } + } +} diff --git a/modules/worker/back/models/worker-time-control-mail.json b/modules/worker/back/models/worker-time-control-mail.json index 78b99881d..87eae9217 100644 --- a/modules/worker/back/models/worker-time-control-mail.json +++ b/modules/worker/back/models/worker-time-control-mail.json @@ -28,6 +28,9 @@ }, "reason": { "type": "string" + }, + "sendedCounter": { + "type": "number" } }, "acls": [ diff --git a/modules/worker/back/models/worker-time-control.js b/modules/worker/back/models/worker-time-control.js index 7339f5d15..d5da680cf 100644 --- a/modules/worker/back/models/worker-time-control.js +++ b/modules/worker/back/models/worker-time-control.js @@ -8,6 +8,8 @@ module.exports = Self => { require('../methods/worker-time-control/sendMail')(Self); require('../methods/worker-time-control/updateWorkerTimeControlMail')(Self); require('../methods/worker-time-control/weeklyHourRecordEmail')(Self); + require('../methods/worker-time-control/getMailStates')(Self); + require('../methods/worker-time-control/resendWeeklyHourEmail')(Self); Self.rewriteDbError(function(err) { if (err.code === 'ER_DUP_ENTRY') diff --git a/modules/worker/back/models/worker.json b/modules/worker/back/models/worker.json index d21094f26..1a9b6ba69 100644 --- a/modules/worker/back/models/worker.json +++ b/modules/worker/back/models/worker.json @@ -2,10 +2,6 @@ "name": "Worker", "description": "Company employees", "base": "Loggable", - "log": { - "model":"WorkerLog", - "showField": "firstName" - }, "options": { "mysql": { "table": "worker" diff --git a/modules/worker/front/calendar/index.html b/modules/worker/front/calendar/index.html index cff4d0bc9..c9eacbd82 100644 --- a/modules/worker/front/calendar/index.html +++ b/modules/worker/front/calendar/index.html @@ -25,11 +25,11 @@
{{'Contract' | translate}} #{{$ctrl.businessId}}
- {{'Used' | translate}} {{$ctrl.contractHolidays.holidaysEnjoyed || 0}} + {{'Used' | translate}} {{$ctrl.contractHolidays.holidaysEnjoyed || 0}} {{'of' | translate}} {{$ctrl.contractHolidays.totalHolidays || 0}} {{'days' | translate}}
- {{'Spent' | translate}} {{$ctrl.contractHolidays.hoursEnjoyed || 0}} + {{'Spent' | translate}} {{$ctrl.contractHolidays.hoursEnjoyed || 0}} {{'of' | translate}} {{$ctrl.contractHolidays.totalHours || 0}} {{'hours' | translate}}
@@ -40,11 +40,11 @@
{{'Year' | translate}} {{$ctrl.year}}
- {{'Used' | translate}} {{$ctrl.yearHolidays.holidaysEnjoyed || 0}} + {{'Used' | translate}} {{$ctrl.yearHolidays.holidaysEnjoyed || 0}} {{'of' | translate}} {{$ctrl.yearHolidays.totalHolidays || 0}} {{'days' | translate}}
- {{'Spent' | translate}} {{$ctrl.yearHolidays.hoursEnjoyed || 0}} + {{'Spent' | translate}} {{$ctrl.yearHolidays.hoursEnjoyed || 0}} {{'of' | translate}} {{$ctrl.yearHolidays.totalHours || 0}} {{'hours' | translate}}
@@ -66,7 +66,7 @@ order="businessFk DESC" limit="5"> -
#{{businessFk}}
+
#{{businessFk}}
{{started | date: 'dd/MM/yyyy'}} - {{ended ? (ended | date: 'dd/MM/yyyy') : 'Indef.'}}
@@ -87,17 +87,17 @@ - Festive + Festive - Current day + Current day
- diff --git a/modules/worker/front/create/index.js b/modules/worker/front/create/index.js index 7e837fe02..7966926b0 100644 --- a/modules/worker/front/create/index.js +++ b/modules/worker/front/create/index.js @@ -13,14 +13,20 @@ export default class Controller extends Section { }); } + get ibanCountry() { + if (!this.worker || !this.worker.iban) return false; + + let countryCode = this.worker.iban.substr(0, 2); + + return countryCode; + } + autofillBic() { if (!this.worker || !this.worker.iban) return; let bankEntityId = parseInt(this.worker.iban.substr(4, 4)); let filter = {where: {id: bankEntityId}}; - if (this.ibanCountry != 'ES') return; - this.$http.get(`BankEntities`, {filter}).then(response => { const hasData = response.data && response.data[0]; diff --git a/modules/worker/front/index.js b/modules/worker/front/index.js index 657f6a8c6..8fad2c0df 100644 --- a/modules/worker/front/index.js +++ b/modules/worker/front/index.js @@ -18,3 +18,6 @@ import './log'; import './dms/index'; import './dms/create'; import './dms/edit'; +import './note/index'; +import './note/create'; + diff --git a/modules/worker/front/locale/es.yml b/modules/worker/front/locale/es.yml index b5bcfefa4..a25377122 100644 --- a/modules/worker/front/locale/es.yml +++ b/modules/worker/front/locale/es.yml @@ -31,3 +31,5 @@ Deallocate PDA: Desasignar PDA PDA deallocated: PDA desasignada PDA allocated: PDA asignada New PDA: Nueva PDA +Notes: Notas +New note: Nueva nota diff --git a/modules/worker/front/note/create/index.html b/modules/worker/front/note/create/index.html new file mode 100644 index 000000000..d09fc2da5 --- /dev/null +++ b/modules/worker/front/note/create/index.html @@ -0,0 +1,30 @@ + + +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/worker/front/note/create/index.js b/modules/worker/front/note/create/index.js new file mode 100644 index 000000000..81ee247db --- /dev/null +++ b/modules/worker/front/note/create/index.js @@ -0,0 +1,21 @@ +import ngModule from '../../module'; +import Section from 'salix/components/section'; + +export default class Controller extends Section { + constructor($element, $) { + super($element, $); + this.note = { + workerFk: parseInt(this.$params.id), + text: null + }; + } + + cancel() { + this.$state.go('worker.card.note.index', {id: this.$params.id}); + } +} + +ngModule.vnComponent('vnNoteWorkerCreate', { + template: require('./index.html'), + controller: Controller +}); diff --git a/modules/worker/front/note/create/index.spec.js b/modules/worker/front/note/create/index.spec.js new file mode 100644 index 000000000..d900c8ee0 --- /dev/null +++ b/modules/worker/front/note/create/index.spec.js @@ -0,0 +1,22 @@ +import './index'; + +describe('Worker', () => { + describe('Component vnNoteWorkerCreate', () => { + let $state; + let controller; + + beforeEach(ngModule('worker')); + + beforeEach(inject(($componentController, _$state_) => { + $state = _$state_; + $state.params.id = '1234'; + const $element = angular.element(''); + controller = $componentController('vnNoteWorkerCreate', {$element, $state}); + })); + + it('should define workerFk using $state.params.id', () => { + expect(controller.note.workerFk).toBe(1234); + expect(controller.note.worker).toBe(undefined); + }); + }); +}); diff --git a/modules/worker/front/note/create/locale/es.yml b/modules/worker/front/note/create/locale/es.yml new file mode 100644 index 000000000..bfe773f48 --- /dev/null +++ b/modules/worker/front/note/create/locale/es.yml @@ -0,0 +1,2 @@ +New note: Nueva nota +Note: Nota \ No newline at end of file diff --git a/modules/worker/front/note/index/index.html b/modules/worker/front/note/index/index.html new file mode 100644 index 000000000..9f5c27008 --- /dev/null +++ b/modules/worker/front/note/index/index.html @@ -0,0 +1,32 @@ + + + + +
+ + {{::note.user.nickname}} + {{::note.created | date:'dd/MM/yyyy HH:mm'}} + + + {{::note.text}} + +
+
+
+ + + diff --git a/modules/worker/front/note/index/index.js b/modules/worker/front/note/index/index.js new file mode 100644 index 000000000..d20971413 --- /dev/null +++ b/modules/worker/front/note/index/index.js @@ -0,0 +1,22 @@ +import ngModule from '../../module'; +import Section from 'salix/components/section'; +import './style.scss'; + +export default class Controller extends Section { + constructor($element, $) { + super($element, $); + this.filter = { + order: 'created DESC', + }; + } +} + +Controller.$inject = ['$element', '$scope']; + +ngModule.vnComponent('vnWorkerNote', { + template: require('./index.html'), + controller: Controller, + bindings: { + worker: '<' + } +}); diff --git a/modules/worker/front/note/index/style.scss b/modules/worker/front/note/index/style.scss new file mode 100644 index 000000000..5ff6baf4f --- /dev/null +++ b/modules/worker/front/note/index/style.scss @@ -0,0 +1,5 @@ +vn-worker-note { + .note:last-child { + margin-bottom: 0; + } +} \ No newline at end of file diff --git a/modules/worker/front/routes.json b/modules/worker/front/routes.json index 64b98bfca..64cb186d6 100644 --- a/modules/worker/front/routes.json +++ b/modules/worker/front/routes.json @@ -11,6 +11,7 @@ ], "card": [ {"state": "worker.card.basicData", "icon": "settings"}, + {"state": "worker.card.note.index", "icon": "insert_drive_file"}, {"state": "worker.card.timeControl", "icon": "access_time"}, {"state": "worker.card.calendar", "icon": "icon-calendar"}, {"state": "worker.card.pda", "icon": "phone_android"}, @@ -72,6 +73,24 @@ "component": "vn-worker-log", "description": "Log", "acl": ["salesAssistant"] + }, { + "url": "/note", + "state": "worker.card.note", + "component": "ui-view", + "abstract": true + }, { + "url": "/index", + "state": "worker.card.note.index", + "component": "vn-worker-note", + "description": "Notes", + "params": { + "worker": "$ctrl.worker" + } + }, { + "url": "/create", + "state": "worker.card.note.create", + "component": "vn-note-worker-create", + "description": "New note" }, { "url": "/pbx", "state": "worker.card.pbx", diff --git a/modules/worker/front/time-control/index.html b/modules/worker/front/time-control/index.html index 681d420d0..044ea4038 100644 --- a/modules/worker/front/time-control/index.html +++ b/modules/worker/front/time-control/index.html @@ -1,7 +1,7 @@ @@ -16,7 +16,7 @@ {{::weekday.dated | date: 'MMMM'}} - - + - - + - + + + + - +
Hours
- -
@@ -106,6 +122,8 @@ vn-id="calendar" class="vn-pt-md" ng-model="$ctrl.date" + format-week="$ctrl.formatWeek($element)" + on-move="$ctrl.getMailStates($date)" has-events="$ctrl.hasEvents($day)">
@@ -166,15 +184,31 @@ vn-id="reason" on-accept="$ctrl.isUnsatisfied()"> - - +
+ + +
- + - \ No newline at end of file + + + + + Are you sure you want to send it? + + + + + + diff --git a/modules/worker/front/time-control/index.js b/modules/worker/front/time-control/index.js index f7379fea0..85ddcedfe 100644 --- a/modules/worker/front/time-control/index.js +++ b/modules/worker/front/time-control/index.js @@ -1,6 +1,7 @@ import ngModule from '../module'; import Section from 'salix/components/section'; import './style.scss'; +import UserError from 'core/lib/user-error'; class Controller extends Section { constructor($element, $, vnWeekDays) { @@ -24,12 +25,31 @@ class Controller extends Section { } this.date = initialDate; + + this.getMailStates(this.date); + } + + get isHr() { + return this.aclService.hasAny(['hr']); + } + + get isHimSelf() { + const userId = window.localStorage.currentUserWorkerId; + return userId == this.$params.id; } get worker() { return this._worker; } + get weekNumber() { + return this.getWeekNumber(this.date); + } + + set weekNumber(value) { + this._weekNumber = value; + } + set worker(value) { this._worker = value; } @@ -68,6 +88,27 @@ class Controller extends Section { } this.fetchHours(); + this.getWeekData(); + } + + getWeekData() { + const filter = { + where: { + workerFk: this.$params.id, + year: this._date.getFullYear(), + week: this.getWeekNumber(this._date) + } + }; + this.$http.get('WorkerTimeControlMails', {filter}) + .then(res => { + const workerTimeControlMail = res.data; + if (!workerTimeControlMail.length) { + this.state = null; + return; + } + this.state = workerTimeControlMail[0].state; + this.reason = workerTimeControlMail[0].reason; + }); } /** @@ -262,7 +303,10 @@ class Controller extends Section { const query = `WorkerTimeControls/${this.worker.id}/addTimeEntry`; this.$http.post(query, entry) - .then(() => this.fetchHours()); + .then(() => { + this.fetchHours(); + this.getMailStates(this.date); + }); } catch (e) { this.vnApp.showError(this.$t(e.message)); return false; @@ -283,6 +327,7 @@ class Controller extends Section { this.$http.post(`WorkerTimeControls/${entryId}/deleteTimeEntry`).then(() => { this.fetchHours(); + this.getMailStates(this.date); this.vnApp.showSuccess(this.$t('Entry removed')); }); } @@ -294,42 +339,56 @@ class Controller extends Section { this.$.editEntry.show($event); } - getWeekNumber(currentDate) { - const startDate = new Date(currentDate.getFullYear(), 0, 1); - let days = Math.floor((currentDate - startDate) / - (24 * 60 * 60 * 1000)); - return Math.ceil(days / 7); + getWeekNumber(date) { + const tempDate = new Date(date); + let dayOfWeek = tempDate.getDay(); + dayOfWeek = (dayOfWeek === 0) ? 7 : dayOfWeek; + const firstDayOfWeek = new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate() - (dayOfWeek - 1)); + const firstDayOfYear = new Date(tempDate.getFullYear(), 0, 1); + const differenceInMilliseconds = firstDayOfWeek.getTime() - firstDayOfYear.getTime(); + const weekNumber = Math.floor(differenceInMilliseconds / (1000 * 60 * 60 * 24 * 7)) + 1; + return weekNumber; } isSatisfied() { - const weekNumber = this.getWeekNumber(this.date); const params = { workerId: this.worker.id, year: this.date.getFullYear(), - week: weekNumber, + week: this.weekNumber, state: 'CONFIRMED' }; const query = `WorkerTimeControls/updateWorkerTimeControlMail`; this.$http.post(query, params).then(() => { + this.getMailStates(this.date); + this.getWeekData(); this.vnApp.showSuccess(this.$t('Data saved!')); }); } isUnsatisfied() { - const weekNumber = this.getWeekNumber(this.date); + if (!this.reason) throw new UserError(`You must indicate a reason`); + const params = { workerId: this.worker.id, year: this.date.getFullYear(), - week: weekNumber, + week: this.weekNumber, state: 'REVISE', reason: this.reason }; const query = `WorkerTimeControls/updateWorkerTimeControlMail`; this.$http.post(query, params).then(() => { + this.getMailStates(this.date); + this.getWeekData(); this.vnApp.showSuccess(this.$t('Data saved!')); }); } + changeState(state, reason) { + this.state = state; + this.reason = reason; + this.repaint(); + } + save() { try { const entry = this.selectedRow; @@ -340,11 +399,83 @@ class Controller extends Section { this.$http.post(query, {direction: entry.direction}) .then(() => this.vnApp.showSuccess(this.$t('Data saved!'))) .then(() => this.$.editEntry.hide()) - .then(() => this.fetchHours()); + .then(() => this.fetchHours()) + .then(() => this.getMailStates(this.date)); } catch (e) { this.vnApp.showError(this.$t(e.message)); } } + + resendEmail() { + const params = { + recipient: this.worker.user.emailUser.email, + week: this.weekNumber, + year: this.date.getFullYear(), + workerId: this.worker.id, + state: 'SENDED' + }; + this.$http.post(`WorkerTimeControls/weekly-hour-hecord-email`, params) + .then(() => { + this.getMailStates(this.date); + this.vnApp.showSuccess(this.$t('Email sended')); + }); + } + + getTime(timeString) { + const [hours, minutes, seconds] = timeString.split(':'); + return [parseInt(hours), parseInt(minutes), parseInt(seconds)]; + } + + getMailStates(date) { + const params = { + month: date.getMonth() + 1, + year: date.getFullYear() + }; + const query = `WorkerTimeControls/${this.$params.id}/getMailStates`; + this.$http.get(query, {params}) + .then(res => { + this.workerTimeControlMails = res.data; + this.repaint(); + }); + } + + formatWeek($element) { + const weekNumberHTML = $element.firstElementChild; + const weekNumberValue = weekNumberHTML.innerHTML; + + if (!this.workerTimeControlMails) return; + const workerTimeControlMail = this.workerTimeControlMails.find( + workerTimeControlMail => workerTimeControlMail.week == weekNumberValue + ); + + if (!workerTimeControlMail) return; + const state = workerTimeControlMail.state; + + if (state == 'CONFIRMED') { + weekNumberHTML.classList.remove('revise'); + weekNumberHTML.classList.remove('sended'); + + weekNumberHTML.classList.add('confirmed'); + weekNumberHTML.setAttribute('title', 'Conforme'); + } + if (state == 'REVISE') { + weekNumberHTML.classList.remove('confirmed'); + weekNumberHTML.classList.remove('sended'); + + weekNumberHTML.classList.add('revise'); + weekNumberHTML.setAttribute('title', 'No conforme'); + } + if (state == 'SENDED') { + weekNumberHTML.classList.add('sended'); + weekNumberHTML.setAttribute('title', 'Pendiente'); + } + } + + repaint() { + let calendars = this.element.querySelectorAll('vn-calendar'); + for (let calendar of calendars) + calendar.$ctrl.repaint(); + } } Controller.$inject = ['$element', '$scope', 'vnWeekDays']; diff --git a/modules/worker/front/time-control/index.spec.js b/modules/worker/front/time-control/index.spec.js index b68162d39..94f9d3d48 100644 --- a/modules/worker/front/time-control/index.spec.js +++ b/modules/worker/front/time-control/index.spec.js @@ -5,12 +5,14 @@ describe('Component vnWorkerTimeControl', () => { let $scope; let $element; let controller; + let $httpParamSerializer; beforeEach(ngModule('worker')); - beforeEach(inject(($componentController, $rootScope, $stateParams, _$httpBackend_) => { + beforeEach(inject(($componentController, $rootScope, $stateParams, _$httpBackend_, _$httpParamSerializer_) => { $stateParams.id = 1; $httpBackend = _$httpBackend_; + $httpParamSerializer = _$httpParamSerializer_; $scope = $rootScope.$new(); $element = angular.element(''); controller = $componentController('vnWorkerTimeControl', {$element, $scope}); @@ -82,6 +84,9 @@ describe('Component vnWorkerTimeControl', () => { $httpBackend.whenRoute('GET', 'Workers/:id/getWorkedHours') .respond(response); + $httpBackend.whenRoute('GET', 'WorkerTimeControlMails') + .respond([]); + today.setHours(0, 0, 0, 0); let weekOffset = today.getDay() - 1; @@ -97,7 +102,6 @@ describe('Component vnWorkerTimeControl', () => { controller.ended = ended; controller.getWorkedHours(controller.started, controller.ended); - $httpBackend.flush(); expect(controller.weekDays.length).toEqual(7); @@ -116,6 +120,13 @@ describe('Component vnWorkerTimeControl', () => { describe('save() ', () => { it(`should make a query an then call to the fetchHours() method`, () => { + const today = Date.vnNew(); + + jest.spyOn(controller, 'getWeekData').mockReturnThis(); + jest.spyOn(controller, 'getMailStates').mockReturnThis(); + + controller.$.model = {applyFilter: jest.fn().mockReturnValue(Promise.resolve())}; + controller.date = today; controller.fetchHours = jest.fn(); controller.selectedRow = {id: 1, timed: Date.vnNew(), direction: 'in'}; controller.$.editEntry = { @@ -152,5 +163,122 @@ describe('Component vnWorkerTimeControl', () => { expect(controller.date.toDateString()).toEqual(date.toDateString()); }); }); + + describe('getWeekData() ', () => { + it(`should make a query an then update the state and reason`, () => { + const today = Date.vnNew(); + const response = [ + { + state: 'SENDED', + reason: null + } + ]; + + controller._date = today; + + $httpBackend.whenRoute('GET', 'WorkerTimeControlMails') + .respond(response); + + controller.getWeekData(); + $httpBackend.flush(); + + expect(controller.state).toBe('SENDED'); + expect(controller.reason).toBe(null); + }); + }); + + describe('isSatisfied() ', () => { + it(`should make a query an then call three methods`, () => { + const today = Date.vnNew(); + jest.spyOn(controller, 'getWeekData').mockReturnThis(); + jest.spyOn(controller, 'getMailStates').mockReturnThis(); + jest.spyOn(controller.vnApp, 'showSuccess'); + + controller.$.model = {applyFilter: jest.fn().mockReturnValue(Promise.resolve())}; + controller.worker = {id: 1}; + controller.date = today; + controller.weekNumber = 1; + + $httpBackend.expect('POST', 'WorkerTimeControls/updateWorkerTimeControlMail').respond(); + controller.isSatisfied(); + $httpBackend.flush(); + + expect(controller.getMailStates).toHaveBeenCalledWith(controller.date); + expect(controller.getWeekData).toHaveBeenCalled(); + expect(controller.vnApp.showSuccess).toHaveBeenCalled(); + }); + }); + + describe('isUnsatisfied() ', () => { + it(`should throw an error is reason is empty`, () => { + let error; + try { + controller.isUnsatisfied(); + } catch (e) { + error = e; + } + + expect(error).toBeDefined(); + expect(error.message).toBe(`You must indicate a reason`); + }); + + it(`should make a query an then call three methods`, () => { + const today = Date.vnNew(); + jest.spyOn(controller, 'getWeekData').mockReturnThis(); + jest.spyOn(controller, 'getMailStates').mockReturnThis(); + jest.spyOn(controller.vnApp, 'showSuccess'); + + controller.$.model = {applyFilter: jest.fn().mockReturnValue(Promise.resolve())}; + controller.worker = {id: 1}; + controller.date = today; + controller.weekNumber = 1; + controller.reason = 'reason'; + + $httpBackend.expect('POST', 'WorkerTimeControls/updateWorkerTimeControlMail').respond(); + controller.isSatisfied(); + $httpBackend.flush(); + + expect(controller.getMailStates).toHaveBeenCalledWith(controller.date); + expect(controller.getWeekData).toHaveBeenCalled(); + expect(controller.vnApp.showSuccess).toHaveBeenCalled(); + }); + }); + + describe('resendEmail() ', () => { + it(`should make a query an then call showSuccess method`, () => { + const today = Date.vnNew(); + + jest.spyOn(controller, 'getWeekData').mockReturnThis(); + jest.spyOn(controller, 'getMailStates').mockReturnThis(); + jest.spyOn(controller.vnApp, 'showSuccess'); + + controller.$.model = {applyFilter: jest.fn().mockReturnValue(Promise.resolve())}; + controller.worker = {id: 1}; + controller.worker = {user: {emailUser: {email: 'employee@verdnatura.es'}}}; + controller.date = today; + controller.weekNumber = 1; + + $httpBackend.expect('POST', 'WorkerTimeControls/weekly-hour-hecord-email').respond(); + controller.resendEmail(); + $httpBackend.flush(); + + expect(controller.vnApp.showSuccess).toHaveBeenCalled(); + }); + }); + + describe('getMailStates() ', () => { + it(`should make a query an then call showSuccess method`, () => { + const today = Date.vnNew(); + jest.spyOn(controller, 'repaint').mockReturnThis(); + + controller.$params = {id: 1}; + + $httpBackend.expect('GET', `WorkerTimeControls/1/getMailStates?month=1&year=2001`).respond(); + controller.getMailStates(today); + $httpBackend.flush(); + + expect(controller.repaint).toHaveBeenCalled(); + }); + }); }); }); diff --git a/modules/worker/front/time-control/locale/es.yml b/modules/worker/front/time-control/locale/es.yml index 2a3bffc00..091c01baa 100644 --- a/modules/worker/front/time-control/locale/es.yml +++ b/modules/worker/front/time-control/locale/es.yml @@ -13,4 +13,10 @@ Entry removed: Fichada borrada The entry type can't be empty: El tipo de fichada no puede quedar vacía Satisfied: Conforme Not satisfied: No conforme -Reason: Motivo \ No newline at end of file +Reason: Motivo +Resend: Reenviar +Email sended: Email enviado +You must indicate a reason: Debes indicar un motivo +Send time control email: Enviar email control horario +Are you sure you want to send it?: ¿Seguro que quieres enviarlo? +Resend email of this week to the user: Reenviar email de esta semana al usuario diff --git a/modules/worker/front/time-control/style.scss b/modules/worker/front/time-control/style.scss index 6a46921a7..9d7545aaf 100644 --- a/modules/worker/front/time-control/style.scss +++ b/modules/worker/front/time-control/style.scss @@ -14,7 +14,7 @@ vn-worker-time-control { align-items: center; justify-content: center; padding: 4px 0; - + & > vn-icon { color: $color-font-secondary; padding-right: 1px; @@ -24,8 +24,29 @@ vn-worker-time-control { .totalBox { max-width: none } + +} + +.reasonDialog{ + min-width: 500px; } .edit-time-entry { width: 200px -} \ No newline at end of file +} + +.right { + float: right; + } + +.confirmed { + color: #97B92F; +} + +.revise { + color: #f61e1e; +} + +.sended { + color: #d19b25; +} diff --git a/modules/zone/back/methods/zone/specs/clone.spec.js b/modules/zone/back/methods/zone/specs/clone.spec.js index 92392d789..1b7393912 100644 --- a/modules/zone/back/methods/zone/specs/clone.spec.js +++ b/modules/zone/back/methods/zone/specs/clone.spec.js @@ -1,6 +1,21 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('agency clone()', () => { + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); + it('should clone a zone', async() => { const tx = await models.Zone.beginTransaction({}); diff --git a/modules/zone/back/methods/zone/specs/exclusionGeo.spec.js b/modules/zone/back/methods/zone/specs/exclusionGeo.spec.js index a34132be4..fbe96fc5f 100644 --- a/modules/zone/back/methods/zone/specs/exclusionGeo.spec.js +++ b/modules/zone/back/methods/zone/specs/exclusionGeo.spec.js @@ -1,6 +1,20 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('zone exclusionGeo()', () => { + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); const zoneId = 1; const today = Date.vnNew(); diff --git a/modules/zone/back/methods/zone/specs/toggleIsIncluded.spec.js b/modules/zone/back/methods/zone/specs/toggleIsIncluded.spec.js index 562e62f5f..746a2d0bd 100644 --- a/modules/zone/back/methods/zone/specs/toggleIsIncluded.spec.js +++ b/modules/zone/back/methods/zone/specs/toggleIsIncluded.spec.js @@ -1,6 +1,21 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('zone toggleIsIncluded()', () => { + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); + it('should return the created location with isIncluded true', async() => { const tx = await models.Zone.beginTransaction({}); diff --git a/modules/zone/back/models/zone-event.json b/modules/zone/back/models/zone-event.json index 7cf4b8301..e477dad6a 100644 --- a/modules/zone/back/models/zone-event.json +++ b/modules/zone/back/models/zone-event.json @@ -1,10 +1,6 @@ { "name": "ZoneEvent", "base": "Loggable", - "log": { - "model":"ZoneLog", - "relation": "zone" - }, "options": { "mysql": { "table": "zoneEvent" @@ -57,4 +53,4 @@ "foreignKey": "zoneFk" } } -} \ No newline at end of file +} diff --git a/modules/zone/back/models/zone-exclusion.json b/modules/zone/back/models/zone-exclusion.json index e8088cd44..00c9145cd 100644 --- a/modules/zone/back/models/zone-exclusion.json +++ b/modules/zone/back/models/zone-exclusion.json @@ -1,10 +1,6 @@ { "name": "ZoneExclusion", "base": "Loggable", - "log": { - "model":"ZoneLog", - "relation": "zone" - }, "options": { "mysql": { "table": "zoneExclusion" @@ -27,4 +23,4 @@ "foreignKey": "zoneFk" } } -} \ No newline at end of file +} diff --git a/modules/zone/back/models/zone-included.json b/modules/zone/back/models/zone-included.json index 595f47a78..61633a3c7 100644 --- a/modules/zone/back/models/zone-included.json +++ b/modules/zone/back/models/zone-included.json @@ -1,11 +1,6 @@ { "name": "ZoneIncluded", "base": "Loggable", - "log": { - "model": "ZoneLog", - "relation": "zone", - "showField": "isIncluded" - }, "options": { "mysql": { "table": "zoneIncluded" @@ -32,4 +27,4 @@ "foreignKey": "geoFk" } } -} \ No newline at end of file +} diff --git a/modules/zone/back/models/zone-warehouse.json b/modules/zone/back/models/zone-warehouse.json index 003e4e3c2..b222e95e7 100644 --- a/modules/zone/back/models/zone-warehouse.json +++ b/modules/zone/back/models/zone-warehouse.json @@ -1,10 +1,6 @@ { "name": "ZoneWarehouse", "base": "Loggable", - "log": { - "model":"ZoneLog", - "relation": "zone" - }, "options": { "mysql": { "table": "zoneWarehouse" @@ -32,4 +28,4 @@ "foreignKey": "warehouseFk" } } -} \ No newline at end of file +} diff --git a/modules/zone/back/models/zone.json b/modules/zone/back/models/zone.json index 1e97c1bad..c86da3d3e 100644 --- a/modules/zone/back/models/zone.json +++ b/modules/zone/back/models/zone.json @@ -1,10 +1,6 @@ { "name": "Zone", "base": "Loggable", - "log": { - "model":"ZoneLog", - "showField": "name" - }, "options": { "mysql": { "table": "zone" @@ -38,6 +34,9 @@ "inflation": { "type": "number" }, + "m3Max": { + "type": "number" + }, "itemMaxSize": { "type": "number" } @@ -56,7 +55,7 @@ "exclusions": { "type": "hasMany", "model": "ZoneExclusion", - "foreignKey": "zoneFk" + "foreignKey": "zoneFk" }, "warehouses": { "type": "hasMany", @@ -69,4 +68,4 @@ "foreignKey": "zoneFk" } } -} \ No newline at end of file +} diff --git a/modules/zone/front/basic-data/index.html b/modules/zone/front/basic-data/index.html index 1836216a2..8d8fc6c56 100644 --- a/modules/zone/front/basic-data/index.html +++ b/modules/zone/front/basic-data/index.html @@ -30,14 +30,21 @@ rule> - + vn-one + label="Max m³" + ng-model="$ctrl.zone.itemMaxSize" + min="0" + vn-acl="deliveryBoss" + rule> + + + =0.10.0" } }, + "node_modules/array-parallel": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/array-parallel/-/array-parallel-0.1.3.tgz", + "integrity": "sha512-TDPTwSWW5E4oiFiKmz6RGJ/a80Y91GuLgUYuLd49+XBS75tYo8PNgaT2K/OxuQYqkoI852MDGBorg9OcUSTQ8w==" + }, + "node_modules/array-series": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/array-series/-/array-series-0.1.5.tgz", + "integrity": "sha512-L0XlBwfx9QetHOsbLDrE/vh2t018w9462HM3iaFfxRiK83aJjAt/Ja3NMkOW7FICwWTlQBa3ZbL5FKhuQWkDrg==" + }, "node_modules/array-slice": { "version": "1.1.0", "dev": true, @@ -3894,7 +3905,8 @@ }, "node_modules/axios": { "version": "1.2.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.2.tgz", + "integrity": "sha512-bz/J4gS2S3I7mpN/YZfGFTqhXTYzRho8Ay38w2otuuDR322KzFIWm/4W2K6gIwvWaws5n+mnb7D1lN9uD+QH6Q==", "dependencies": { "follow-redirects": "^1.15.0", "form-data": "^4.0.0", @@ -4201,7 +4213,8 @@ }, "node_modules/base64url": { "version": "3.0.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", + "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==", "engines": { "node": ">=6.0.0" } @@ -4696,7 +4709,8 @@ }, "node_modules/buffer-crc32": { "version": "0.2.13", - "license": "MIT", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "engines": { "node": "*" } @@ -5429,17 +5443,6 @@ "node": ">=0.10.0" } }, - "node_modules/color": { - "version": "4.2.3", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1", - "color-string": "^1.9.0" - }, - "engines": { - "node": ">=12.5.0" - } - }, "node_modules/color-convert": { "version": "2.0.1", "license": "MIT", @@ -5454,14 +5457,6 @@ "version": "1.1.4", "license": "MIT" }, - "node_modules/color-string": { - "version": "1.9.1", - "license": "MIT", - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, "node_modules/color-support": { "version": "1.1.3", "license": "ISC", @@ -6064,6 +6059,13 @@ "version": "0.6.3", "license": "MIT" }, + "node_modules/date-format": { + "version": "4.0.14", + "license": "MIT", + "engines": { + "node": ">=4.0" + } + }, "node_modules/dateformat": { "version": "2.2.0", "dev": true, @@ -6127,6 +6129,7 @@ }, "node_modules/deep-extend": { "version": "0.6.0", + "dev": true, "license": "MIT", "engines": { "node": ">=4.0.0" @@ -6465,7 +6468,8 @@ }, "node_modules/devtools-protocol": { "version": "0.0.1045489", - "license": "BSD-3-Clause" + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1045489.tgz", + "integrity": "sha512-D+PTmWulkuQW4D1NTiCRCFxF7pQPn0hgp4YyX4wAQ6xYXKOadSWPR3ENGDQ47MW/Ewc9v2rpC/UEEGahgBYpSQ==" }, "node_modules/diff": { "version": "1.4.0", @@ -7607,13 +7611,6 @@ "node": ">=0.10.0" } }, - "node_modules/expand-template": { - "version": "2.0.3", - "license": "(MIT OR WTFPL)", - "engines": { - "node": ">=6" - } - }, "node_modules/expand-tilde": { "version": "2.0.2", "dev": true, @@ -7833,7 +7830,8 @@ }, "node_modules/extract-zip": { "version": "2.0.1", - "license": "BSD-2-Clause", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", "dependencies": { "debug": "^4.1.1", "get-stream": "^5.1.0", @@ -7851,7 +7849,8 @@ }, "node_modules/extract-zip/node_modules/debug": { "version": "4.3.4", - "license": "MIT", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dependencies": { "ms": "2.1.2" }, @@ -7866,7 +7865,8 @@ }, "node_modules/extract-zip/node_modules/ms": { "version": "2.1.2", - "license": "MIT" + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/extsprintf": { "version": "1.4.1", @@ -7955,7 +7955,8 @@ }, "node_modules/fd-slicer": { "version": "1.1.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", "dependencies": { "pend": "~1.2.0" } @@ -8358,7 +8359,6 @@ }, "node_modules/flatted": { "version": "3.2.7", - "dev": true, "license": "ISC" }, "node_modules/flush-write-stream": { @@ -8399,13 +8399,14 @@ }, "node_modules/follow-redirects": { "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", "funding": [ { "type": "individual", "url": "https://github.com/sponsors/RubenVerborgh" } ], - "license": "MIT", "engines": { "node": ">=4.0" }, @@ -8443,7 +8444,8 @@ }, "node_modules/form-data": { "version": "4.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -8863,10 +8865,6 @@ "assert-plus": "^1.0.0" } }, - "node_modules/github-from-package": { - "version": "0.0.0", - "license": "MIT" - }, "node_modules/glob": { "version": "7.2.0", "license": "ISC", @@ -9267,6 +9265,67 @@ "node": ">= 0.10" } }, + "node_modules/gm": { + "version": "1.25.0", + "resolved": "https://registry.npmjs.org/gm/-/gm-1.25.0.tgz", + "integrity": "sha512-4kKdWXTtgQ4biIo7hZA396HT062nDVVHPjQcurNZ3o/voYN+o5FUC5kOwuORbpExp3XbTJ3SU7iRipiIhQtovw==", + "dependencies": { + "array-parallel": "~0.1.3", + "array-series": "~0.1.5", + "cross-spawn": "^4.0.0", + "debug": "^3.1.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/gm/node_modules/cross-spawn": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", + "integrity": "sha512-yAXz/pA1tD8Gtg2S98Ekf/sewp3Lcp3YoFKJ4Hkp5h5yLWnKVTDU0kwjKJ8NDCYcfTLfyGkzTikst+jWypT1iA==", + "dependencies": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, + "node_modules/gm/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/gm/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/gm/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/gm/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/gm/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==" + }, "node_modules/google-auth-library": { "version": "3.1.2", "license": "Apache-2.0", @@ -11427,6 +11486,7 @@ }, "node_modules/ini": { "version": "1.3.8", + "dev": true, "license": "ISC" }, "node_modules/internal-ip": { @@ -11556,10 +11616,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-arrayish": { - "version": "0.3.2", - "license": "MIT" - }, "node_modules/is-bigint": { "version": "1.0.4", "dev": true, @@ -12224,8 +12280,9 @@ }, "node_modules/jasmine": { "version": "4.5.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-4.5.0.tgz", + "integrity": "sha512-9olGRvNZyADIwYL9XBNBst5BTU/YaePzuddK+YRslc7rI9MdTIE4r3xaBKbv2GEmzYYUfMOdTR8/i6JfLZaxSQ==", "dev": true, - "license": "MIT", "dependencies": { "glob": "^7.1.6", "jasmine-core": "^4.5.0" @@ -12236,8 +12293,9 @@ }, "node_modules/jasmine-core": { "version": "4.5.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.5.0.tgz", + "integrity": "sha512-9PMzyvhtocxb3aXJVOPqBDswdgyAeSB81QnLop4npOpbqnheaTEwPc9ZloQeVswugPManznQBjD8kWDTjlnHuw==", + "dev": true }, "node_modules/jasmine-reporters": { "version": "2.5.0", @@ -13129,6 +13187,66 @@ "xmlcreate": "^1.0.1" } }, + "node_modules/jsbarcode": { + "version": "3.11.5", + "resolved": "https://registry.npmjs.org/jsbarcode/-/jsbarcode-3.11.5.tgz", + "integrity": "sha512-zv3KsH51zD00I/LrFzFSM6dst7rDn0vIMzaiZFL7qusTjPZiPtxg3zxetp0RR7obmjTw4f6NyGgbdkBCgZUIrA==", + "bin": { + "auto.js": "bin/barcodes/CODE128/auto.js", + "Barcode.js": "bin/barcodes/Barcode.js", + "barcodes": "bin/barcodes", + "canvas.js": "bin/renderers/canvas.js", + "checksums.js": "bin/barcodes/MSI/checksums.js", + "codabar": "bin/barcodes/codabar", + "CODE128": "bin/barcodes/CODE128", + "CODE128_AUTO.js": "bin/barcodes/CODE128/CODE128_AUTO.js", + "CODE128.js": "bin/barcodes/CODE128/CODE128.js", + "CODE128A.js": "bin/barcodes/CODE128/CODE128A.js", + "CODE128B.js": "bin/barcodes/CODE128/CODE128B.js", + "CODE128C.js": "bin/barcodes/CODE128/CODE128C.js", + "CODE39": "bin/barcodes/CODE39", + "constants.js": "bin/barcodes/ITF/constants.js", + "defaults.js": "bin/options/defaults.js", + "EAN_UPC": "bin/barcodes/EAN_UPC", + "EAN.js": "bin/barcodes/EAN_UPC/EAN.js", + "EAN13.js": "bin/barcodes/EAN_UPC/EAN13.js", + "EAN2.js": "bin/barcodes/EAN_UPC/EAN2.js", + "EAN5.js": "bin/barcodes/EAN_UPC/EAN5.js", + "EAN8.js": "bin/barcodes/EAN_UPC/EAN8.js", + "encoder.js": "bin/barcodes/EAN_UPC/encoder.js", + "ErrorHandler.js": "bin/exceptions/ErrorHandler.js", + "exceptions": "bin/exceptions", + "exceptions.js": "bin/exceptions/exceptions.js", + "fixOptions.js": "bin/help/fixOptions.js", + "GenericBarcode": "bin/barcodes/GenericBarcode", + "getOptionsFromElement.js": "bin/help/getOptionsFromElement.js", + "getRenderProperties.js": "bin/help/getRenderProperties.js", + "help": "bin/help", + "index.js": "bin/renderers/index.js", + "index.tmp.js": "bin/barcodes/index.tmp.js", + "ITF": "bin/barcodes/ITF", + "ITF.js": "bin/barcodes/ITF/ITF.js", + "ITF14.js": "bin/barcodes/ITF/ITF14.js", + "JsBarcode.js": "bin/JsBarcode.js", + "linearizeEncodings.js": "bin/help/linearizeEncodings.js", + "merge.js": "bin/help/merge.js", + "MSI": "bin/barcodes/MSI", + "MSI.js": "bin/barcodes/MSI/MSI.js", + "MSI10.js": "bin/barcodes/MSI/MSI10.js", + "MSI1010.js": "bin/barcodes/MSI/MSI1010.js", + "MSI11.js": "bin/barcodes/MSI/MSI11.js", + "MSI1110.js": "bin/barcodes/MSI/MSI1110.js", + "object.js": "bin/renderers/object.js", + "options": "bin/options", + "optionsFromStrings.js": "bin/help/optionsFromStrings.js", + "pharmacode": "bin/barcodes/pharmacode", + "renderers": "bin/renderers", + "shared.js": "bin/renderers/shared.js", + "svg.js": "bin/renderers/svg.js", + "UPC.js": "bin/barcodes/EAN_UPC/UPC.js", + "UPCE.js": "bin/barcodes/EAN_UPC/UPCE.js" + } + }, "node_modules/jsbn": { "version": "0.1.1", "license": "MIT" @@ -13879,6 +13997,39 @@ "dev": true, "license": "MIT" }, + "node_modules/log4js": { + "version": "6.7.0", + "license": "Apache-2.0", + "dependencies": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "flatted": "^3.2.7", + "rfdc": "^1.3.0", + "streamroller": "^3.1.3" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/log4js/node_modules/debug": { + "version": "4.3.4", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/log4js/node_modules/ms": { + "version": "2.1.2", + "license": "MIT" + }, "node_modules/loglevel": { "version": "1.8.0", "dev": true, @@ -15426,10 +15577,6 @@ "node": ">=0.10.0" } }, - "node_modules/napi-build-utils": { - "version": "1.0.2", - "license": "MIT" - }, "node_modules/natural-compare": { "version": "1.4.0", "dev": true, @@ -15471,43 +15618,6 @@ "node": ">=4.0.0" } }, - "node_modules/node-abi": { - "version": "3.28.0", - "license": "MIT", - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-abi/node_modules/lru-cache": { - "version": "6.0.0", - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-abi/node_modules/semver": { - "version": "7.3.8", - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-abi/node_modules/yallist": { - "version": "4.0.0", - "license": "ISC" - }, "node_modules/node-addon-api": { "version": "5.0.0", "license": "MIT" @@ -17096,7 +17206,8 @@ }, "node_modules/pend": { "version": "1.2.0", - "license": "MIT" + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==" }, "node_modules/performance-now": { "version": "2.1.0", @@ -17354,30 +17465,6 @@ "node": ">=0.10.0" } }, - "node_modules/prebuild-install": { - "version": "7.1.1", - "license": "MIT", - "dependencies": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, - "bin": { - "prebuild-install": "bin.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/precond": { "version": "0.2.3", "engines": { @@ -17496,7 +17583,8 @@ }, "node_modules/proxy-from-env": { "version": "1.1.0", - "license": "MIT" + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, "node_modules/prr": { "version": "1.0.1", @@ -17579,8 +17667,9 @@ }, "node_modules/puppeteer": { "version": "18.2.1", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-18.2.1.tgz", + "integrity": "sha512-7+UhmYa7wxPh2oMRwA++k8UGVDxh3YdWFB52r9C3tM81T6BU7cuusUSxImz0GEYSOYUKk/YzIhkQ6+vc0gHbxQ==", "hasInstallScript": true, - "license": "Apache-2.0", "dependencies": { "https-proxy-agent": "5.0.1", "progress": "2.0.3", @@ -17591,9 +17680,39 @@ "node": ">=14.1.0" } }, + "node_modules/puppeteer-cluster": { + "version": "0.23.0", + "license": "MIT", + "dependencies": { + "debug": "^4.3.3" + }, + "peerDependencies": { + "puppeteer": ">=1.5.0" + } + }, + "node_modules/puppeteer-cluster/node_modules/debug": { + "version": "4.3.4", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/puppeteer-cluster/node_modules/ms": { + "version": "2.1.2", + "license": "MIT" + }, "node_modules/puppeteer-core": { "version": "18.2.1", - "license": "Apache-2.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-18.2.1.tgz", + "integrity": "sha512-MRtTAZfQTluz3U2oU/X2VqVWPcR1+94nbA2V6ZrSZRVEwLqZ8eclZ551qGFQD/vD2PYqHJwWOW/fpC721uznVw==", "dependencies": { "cross-fetch": "3.1.5", "debug": "4.3.4", @@ -17612,7 +17731,8 @@ }, "node_modules/puppeteer-core/node_modules/agent-base": { "version": "6.0.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "dependencies": { "debug": "4" }, @@ -17622,7 +17742,8 @@ }, "node_modules/puppeteer-core/node_modules/debug": { "version": "4.3.4", - "license": "MIT", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dependencies": { "ms": "2.1.2" }, @@ -17637,7 +17758,8 @@ }, "node_modules/puppeteer-core/node_modules/https-proxy-agent": { "version": "5.0.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", "dependencies": { "agent-base": "6", "debug": "4" @@ -17648,11 +17770,13 @@ }, "node_modules/puppeteer-core/node_modules/ms": { "version": "2.1.2", - "license": "MIT" + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/puppeteer-core/node_modules/ws": { "version": "8.9.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.9.0.tgz", + "integrity": "sha512-Ja7nszREasGaYUYCI2k4lCKIRTt+y7XuqVoHR44YpI49TtryyqbqvDMn5eqfW7e6HzTukDRIsXqzVHScqRcafg==", "engines": { "node": ">=10.0.0" }, @@ -17835,6 +17959,7 @@ }, "node_modules/rc": { "version": "1.2.8", + "dev": true, "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", "dependencies": { "deep-extend": "^0.6.0", @@ -18542,7 +18667,8 @@ }, "node_modules/request/node_modules/form-data": { "version": "2.3.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", @@ -18708,6 +18834,10 @@ "version": "2.1.2", "license": "MIT" }, + "node_modules/rfdc": { + "version": "1.3.0", + "license": "MIT" + }, "node_modules/rimraf": { "version": "3.0.2", "license": "ISC", @@ -19559,54 +19689,6 @@ "node": ">=8" } }, - "node_modules/sharp": { - "version": "0.31.3", - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "color": "^4.2.3", - "detect-libc": "^2.0.1", - "node-addon-api": "^5.0.0", - "prebuild-install": "^7.1.1", - "semver": "^7.3.8", - "simple-get": "^4.0.1", - "tar-fs": "^2.1.1", - "tunnel-agent": "^0.6.0" - }, - "engines": { - "node": ">=14.15.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/sharp/node_modules/lru-cache": { - "version": "6.0.0", - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/sharp/node_modules/semver": { - "version": "7.3.8", - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/sharp/node_modules/yallist": { - "version": "4.0.0", - "license": "ISC" - }, "node_modules/shebang-command": { "version": "2.0.0", "license": "MIT", @@ -19665,77 +19747,6 @@ "version": "3.0.7", "license": "ISC" }, - "node_modules/simple-concat": { - "version": "1.0.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/simple-get": { - "version": "4.0.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "node_modules/simple-get/node_modules/decompress-response": { - "version": "6.0.0", - "license": "MIT", - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/simple-get/node_modules/mimic-response": { - "version": "3.1.0", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, "node_modules/simple-update-notifier": { "version": "1.0.7", "dev": true, @@ -20476,6 +20487,49 @@ "version": "1.0.1", "license": "MIT" }, + "node_modules/streamroller": { + "version": "3.1.3", + "license": "MIT", + "dependencies": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/streamroller/node_modules/debug": { + "version": "4.3.4", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/streamroller/node_modules/fs-extra": { + "version": "8.1.0", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/streamroller/node_modules/ms": { + "version": "2.1.2", + "license": "MIT" + }, "node_modules/streamsearch": { "version": "0.1.2", "engines": { @@ -20593,6 +20647,7 @@ }, "node_modules/strip-json-comments": { "version": "2.0.1", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -22080,7 +22135,8 @@ }, "node_modules/unbzip2-stream": { "version": "1.4.3", - "license": "MIT", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", "dependencies": { "buffer": "^5.2.1", "through": "^2.3.8" @@ -22088,6 +22144,8 @@ }, "node_modules/unbzip2-stream/node_modules/base64-js": { "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "funding": [ { "type": "github", @@ -22101,11 +22159,12 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "license": "MIT" + ] }, "node_modules/unbzip2-stream/node_modules/buffer": { "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "funding": [ { "type": "github", @@ -22120,7 +22179,6 @@ "url": "https://feross.org/support" } ], - "license": "MIT", "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -24399,6 +24457,14 @@ "version": "1.0.2", "license": "Apache-2.0" }, + "node_modules/xmldom": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.6.0.tgz", + "integrity": "sha512-iAcin401y58LckRZ0TkI4k0VSM1Qg0KGSc3i8rU+xrxe19A/BN1zHyVSJY7uoutVlaTSzYyk/v5AmkewAP7jtg==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/xtend": { "version": "1.0.3", "engines": { @@ -24521,7 +24587,8 @@ }, "node_modules/yauzl": { "version": "2.10.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" @@ -24550,38 +24617,6 @@ "xmldom": "^0.6.0" } }, - "print/node_modules/@babel/code-frame": { - "version": "7.18.6", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/highlight": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "print/node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, - "print/node_modules/@babel/highlight": { - "version": "7.18.6", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "print/node_modules/@babel/parser": { "version": "7.19.3", "license": "MIT", @@ -24592,21 +24627,6 @@ "node": ">=6.0.0" } }, - "print/node_modules/@types/node": { - "version": "18.14.2", - "license": "MIT", - "optional": true, - "peer": true - }, - "print/node_modules/@types/yauzl": { - "version": "2.10.0", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@types/node": "*" - } - }, "print/node_modules/@vue/compiler-sfc": { "version": "2.7.10", "dependencies": { @@ -24615,17 +24635,6 @@ "source-map": "^0.6.1" } }, - "print/node_modules/agent-base": { - "version": "6.0.2", - "license": "MIT", - "peer": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, "print/node_modules/ajv": { "version": "6.12.6", "license": "MIT", @@ -24697,30 +24706,6 @@ "version": "1.11.0", "license": "MIT" }, - "print/node_modules/balanced-match": { - "version": "1.0.2", - "license": "MIT", - "peer": true - }, - "print/node_modules/base64-js": { - "version": "1.5.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "peer": true - }, "print/node_modules/bcrypt-pbkdf": { "version": "1.0.2", "license": "BSD-3-Clause", @@ -24728,68 +24713,10 @@ "tweetnacl": "^0.14.3" } }, - "print/node_modules/bl": { - "version": "4.1.0", - "license": "MIT", - "peer": true, - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, "print/node_modules/boolbase": { "version": "1.0.0", "license": "ISC" }, - "print/node_modules/brace-expansion": { - "version": "1.1.11", - "license": "MIT", - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "print/node_modules/buffer": { - "version": "5.7.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "print/node_modules/buffer-crc32": { - "version": "0.2.13", - "license": "MIT", - "peer": true, - "engines": { - "node": "*" - } - }, - "print/node_modules/callsites": { - "version": "3.1.0", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6" - } - }, "print/node_modules/camelcase": { "version": "5.3.1", "license": "MIT", @@ -24838,22 +24765,6 @@ "node": ">= 0.6" } }, - "print/node_modules/chownr": { - "version": "1.1.4", - "license": "ISC", - "peer": true - }, - "print/node_modules/chromium-bidi": { - "version": "0.4.4", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "mitt": "3.0.0" - }, - "peerDependencies": { - "devtools-protocol": "*" - } - }, "print/node_modules/cliui": { "version": "6.0.0", "license": "ISC", @@ -24888,53 +24799,10 @@ "version": "2.20.3", "license": "MIT" }, - "print/node_modules/concat-map": { - "version": "0.0.1", - "license": "MIT", - "peer": true - }, "print/node_modules/core-util-is": { "version": "1.0.2", "license": "MIT" }, - "print/node_modules/cosmiconfig": { - "version": "8.0.0", - "license": "MIT", - "peer": true, - "dependencies": { - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "print/node_modules/cosmiconfig/node_modules/argparse": { - "version": "2.0.1", - "license": "Python-2.0", - "peer": true - }, - "print/node_modules/cosmiconfig/node_modules/js-yaml": { - "version": "4.1.0", - "license": "MIT", - "peer": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "print/node_modules/cross-fetch": { - "version": "3.1.5", - "license": "MIT", - "peer": true, - "dependencies": { - "node-fetch": "2.6.7" - } - }, "print/node_modules/cross-spawn": { "version": "6.0.5", "license": "MIT", @@ -24991,28 +24859,6 @@ "node": ">= 4" } }, - "print/node_modules/date-format": { - "version": "4.0.14", - "license": "MIT", - "engines": { - "node": ">=4.0" - } - }, - "print/node_modules/debug": { - "version": "4.3.4", - "license": "MIT", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "print/node_modules/decamelize": { "version": "1.2.0", "license": "MIT", @@ -25041,11 +24887,6 @@ "node": ">=0.10" } }, - "print/node_modules/devtools-protocol": { - "version": "0.0.1094867", - "license": "BSD-3-Clause", - "peer": true - }, "print/node_modules/dijkstrajs": { "version": "1.0.2", "license": "MIT" @@ -25092,26 +24933,10 @@ "version": "1.0.3", "license": "MIT" }, - "print/node_modules/end-of-stream": { - "version": "1.4.4", - "license": "MIT", - "peer": true, - "dependencies": { - "once": "^1.4.0" - } - }, "print/node_modules/entities": { "version": "1.1.2", "license": "BSD-2-Clause" }, - "print/node_modules/error-ex": { - "version": "1.3.2", - "license": "MIT", - "peer": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, "print/node_modules/escape-string-regexp": { "version": "1.0.5", "license": "MIT", @@ -25134,25 +24959,6 @@ "version": "3.0.2", "license": "MIT" }, - "print/node_modules/extract-zip": { - "version": "2.0.1", - "license": "BSD-2-Clause", - "peer": true, - "dependencies": { - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" - }, - "engines": { - "node": ">= 10.17.0" - }, - "optionalDependencies": { - "@types/yauzl": "^2.9.1" - } - }, "print/node_modules/extsprintf": { "version": "1.3.0", "engines": [ @@ -25168,14 +24974,6 @@ "version": "2.1.0", "license": "MIT" }, - "print/node_modules/fd-slicer": { - "version": "1.1.0", - "license": "MIT", - "peer": true, - "dependencies": { - "pend": "~1.2.0" - } - }, "print/node_modules/find-up": { "version": "4.1.0", "license": "MIT", @@ -25187,10 +24985,6 @@ "node": ">=8" } }, - "print/node_modules/flatted": { - "version": "3.2.7", - "license": "ISC" - }, "print/node_modules/forever-agent": { "version": "0.6.1", "license": "Apache-2.0", @@ -25210,11 +25004,6 @@ "node": ">= 0.12" } }, - "print/node_modules/fs-constants": { - "version": "1.0.0", - "license": "MIT", - "peer": true - }, "print/node_modules/fs-extra": { "version": "7.0.1", "license": "MIT", @@ -25227,11 +25016,6 @@ "node": ">=6 <7 || >=8" } }, - "print/node_modules/fs.realpath": { - "version": "1.0.0", - "license": "ISC", - "peer": true - }, "print/node_modules/function-bind": { "version": "1.1.1", "license": "MIT" @@ -25250,20 +25034,6 @@ "node": "6.* || 8.* || >= 10.*" } }, - "print/node_modules/get-stream": { - "version": "5.2.0", - "license": "MIT", - "peer": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "print/node_modules/getpass": { "version": "0.1.7", "license": "MIT", @@ -25271,25 +25041,6 @@ "assert-plus": "^1.0.0" } }, - "print/node_modules/glob": { - "version": "7.2.3", - "license": "ISC", - "peer": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "print/node_modules/graceful-fs": { "version": "4.2.10", "license": "ISC" @@ -25365,18 +25116,6 @@ "npm": ">=1.3.7" } }, - "print/node_modules/https-proxy-agent": { - "version": "5.0.1", - "license": "MIT", - "peer": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, "print/node_modules/iconv-lite": { "version": "0.5.2", "license": "MIT", @@ -25387,25 +25126,6 @@ "node": ">=0.10.0" } }, - "print/node_modules/ieee754": { - "version": "1.2.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause", - "peer": true - }, "print/node_modules/image-size": { "version": "0.7.5", "license": "MIT", @@ -25416,30 +25136,6 @@ "node": ">=6.9.0" } }, - "print/node_modules/import-fresh": { - "version": "3.3.0", - "license": "MIT", - "peer": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "print/node_modules/inflight": { - "version": "1.0.6", - "license": "ISC", - "peer": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "print/node_modules/inherits": { "version": "2.0.4", "license": "ISC" @@ -25448,11 +25144,6 @@ "version": "1.2.5", "license": "MIT" }, - "print/node_modules/is-arrayish": { - "version": "0.2.1", - "license": "MIT", - "peer": true - }, "print/node_modules/is-core-module": { "version": "2.10.0", "license": "MIT", @@ -25486,11 +25177,6 @@ "version": "0.1.2", "license": "MIT" }, - "print/node_modules/js-tokens": { - "version": "4.0.0", - "license": "MIT", - "peer": true - }, "print/node_modules/js-yaml": { "version": "3.14.1", "license": "MIT", @@ -25502,61 +25188,10 @@ "js-yaml": "bin/js-yaml.js" } }, - "print/node_modules/jsbarcode": { - "version": "3.11.5", - "license": "MIT", - "bin": { - "auto.js": "bin/barcodes/CODE128/auto.js", - "Barcode.js": "bin/barcodes/Barcode.js", - "canvas.js": "bin/renderers/canvas.js", - "checksums.js": "bin/barcodes/MSI/checksums.js", - "CODE128_AUTO.js": "bin/barcodes/CODE128/CODE128_AUTO.js", - "CODE128.js": "bin/barcodes/CODE128/CODE128.js", - "CODE128A.js": "bin/barcodes/CODE128/CODE128A.js", - "CODE128B.js": "bin/barcodes/CODE128/CODE128B.js", - "CODE128C.js": "bin/barcodes/CODE128/CODE128C.js", - "constants.js": "bin/barcodes/ITF/constants.js", - "defaults.js": "bin/options/defaults.js", - "EAN.js": "bin/barcodes/EAN_UPC/EAN.js", - "EAN13.js": "bin/barcodes/EAN_UPC/EAN13.js", - "EAN2.js": "bin/barcodes/EAN_UPC/EAN2.js", - "EAN5.js": "bin/barcodes/EAN_UPC/EAN5.js", - "EAN8.js": "bin/barcodes/EAN_UPC/EAN8.js", - "encoder.js": "bin/barcodes/EAN_UPC/encoder.js", - "ErrorHandler.js": "bin/exceptions/ErrorHandler.js", - "exceptions.js": "bin/exceptions/exceptions.js", - "fixOptions.js": "bin/help/fixOptions.js", - "getOptionsFromElement.js": "bin/help/getOptionsFromElement.js", - "getRenderProperties.js": "bin/help/getRenderProperties.js", - "index.js": "bin/renderers/index.js", - "index.tmp.js": "bin/barcodes/index.tmp.js", - "ITF.js": "bin/barcodes/ITF/ITF.js", - "ITF14.js": "bin/barcodes/ITF/ITF14.js", - "JsBarcode.js": "bin/JsBarcode.js", - "linearizeEncodings.js": "bin/help/linearizeEncodings.js", - "merge.js": "bin/help/merge.js", - "MSI.js": "bin/barcodes/MSI/MSI.js", - "MSI10.js": "bin/barcodes/MSI/MSI10.js", - "MSI1010.js": "bin/barcodes/MSI/MSI1010.js", - "MSI11.js": "bin/barcodes/MSI/MSI11.js", - "MSI1110.js": "bin/barcodes/MSI/MSI1110.js", - "object.js": "bin/renderers/object.js", - "optionsFromStrings.js": "bin/help/optionsFromStrings.js", - "shared.js": "bin/renderers/shared.js", - "svg.js": "bin/renderers/svg.js", - "UPC.js": "bin/barcodes/EAN_UPC/UPC.js", - "UPCE.js": "bin/barcodes/EAN_UPC/UPCE.js" - } - }, "print/node_modules/jsbn": { "version": "0.1.1", "license": "MIT" }, - "print/node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "license": "MIT", - "peer": true - }, "print/node_modules/json-schema": { "version": "0.4.0", "license": "(AFL-2.1 OR BSD-3-Clause)" @@ -25615,11 +25250,6 @@ "node": ">=4.2.0" } }, - "print/node_modules/lines-and-columns": { - "version": "1.2.4", - "license": "MIT", - "peer": true - }, "print/node_modules/locate-path": { "version": "5.0.0", "license": "MIT", @@ -25705,20 +25335,6 @@ "version": "4.5.0", "license": "MIT" }, - "print/node_modules/log4js": { - "version": "6.8.0", - "license": "Apache-2.0", - "dependencies": { - "date-format": "^4.0.14", - "debug": "^4.3.4", - "flatted": "^3.2.7", - "rfdc": "^1.3.0", - "streamroller": "^3.1.5" - }, - "engines": { - "node": ">=8.0" - } - }, "print/node_modules/long": { "version": "4.0.0", "license": "Apache-2.0" @@ -25761,31 +25377,6 @@ "node": ">= 6.0" } }, - "print/node_modules/minimatch": { - "version": "3.1.2", - "license": "ISC", - "peer": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "print/node_modules/mitt": { - "version": "3.0.0", - "license": "MIT", - "peer": true - }, - "print/node_modules/mkdirp-classic": { - "version": "0.5.3", - "license": "MIT", - "peer": true - }, - "print/node_modules/ms": { - "version": "2.1.2", - "license": "MIT" - }, "print/node_modules/mysql2": { "version": "1.7.0", "license": "MIT", @@ -25839,25 +25430,6 @@ "version": "1.0.5", "license": "MIT" }, - "print/node_modules/node-fetch": { - "version": "2.6.7", - "license": "MIT", - "peer": true, - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, "print/node_modules/nodemailer": { "version": "4.7.0", "license": "MIT", @@ -25879,14 +25451,6 @@ "node": "*" } }, - "print/node_modules/once": { - "version": "1.4.0", - "license": "ISC", - "peer": true, - "dependencies": { - "wrappy": "1" - } - }, "print/node_modules/p-limit": { "version": "2.3.0", "license": "MIT", @@ -25917,34 +25481,6 @@ "node": ">=6" } }, - "print/node_modules/parent-module": { - "version": "1.0.1", - "license": "MIT", - "peer": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "print/node_modules/parse-json": { - "version": "5.2.0", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "print/node_modules/path-exists": { "version": "4.0.0", "license": "MIT", @@ -25952,14 +25488,6 @@ "node": ">=8" } }, - "print/node_modules/path-is-absolute": { - "version": "1.0.1", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "print/node_modules/path-key": { "version": "2.0.1", "license": "MIT", @@ -25971,19 +25499,6 @@ "version": "1.0.7", "license": "MIT" }, - "print/node_modules/path-type": { - "version": "4.0.0", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "print/node_modules/pend": { - "version": "1.2.0", - "license": "MIT", - "peer": true - }, "print/node_modules/performance-now": { "version": "2.1.0", "license": "MIT" @@ -26021,19 +25536,6 @@ "node": "^10 || ^12 || >=14" } }, - "print/node_modules/progress": { - "version": "2.0.3", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.4.0" - } - }, - "print/node_modules/proxy-from-env": { - "version": "1.1.0", - "license": "MIT", - "peer": true - }, "print/node_modules/pseudomap": { "version": "1.0.2", "license": "ISC" @@ -26042,15 +25544,6 @@ "version": "1.9.0", "license": "MIT" }, - "print/node_modules/pump": { - "version": "3.0.0", - "license": "MIT", - "peer": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "print/node_modules/punycode": { "version": "2.1.1", "license": "MIT", @@ -26058,61 +25551,6 @@ "node": ">=6" } }, - "print/node_modules/puppeteer": { - "version": "19.7.2", - "hasInstallScript": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "cosmiconfig": "8.0.0", - "https-proxy-agent": "5.0.1", - "progress": "2.0.3", - "proxy-from-env": "1.1.0", - "puppeteer-core": "19.7.2" - }, - "engines": { - "node": ">=14.1.0" - } - }, - "print/node_modules/puppeteer-cluster": { - "version": "0.23.0", - "license": "MIT", - "dependencies": { - "debug": "^4.3.3" - }, - "peerDependencies": { - "puppeteer": ">=1.5.0" - } - }, - "print/node_modules/puppeteer-core": { - "version": "19.7.2", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "chromium-bidi": "0.4.4", - "cross-fetch": "3.1.5", - "debug": "4.3.4", - "devtools-protocol": "0.0.1094867", - "extract-zip": "2.0.1", - "https-proxy-agent": "5.0.1", - "proxy-from-env": "1.1.0", - "rimraf": "3.0.2", - "tar-fs": "2.1.1", - "unbzip2-stream": "1.4.3", - "ws": "8.11.0" - }, - "engines": { - "node": ">=14.1.0" - }, - "peerDependencies": { - "typescript": ">= 4.7.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, "print/node_modules/qrcode": { "version": "1.5.1", "license": "MIT", @@ -26210,32 +25648,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "print/node_modules/resolve-from": { - "version": "4.0.0", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=4" - } - }, - "print/node_modules/rfdc": { - "version": "1.3.0", - "license": "MIT" - }, - "print/node_modules/rimraf": { - "version": "3.0.2", - "license": "ISC", - "peer": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "print/node_modules/safe-buffer": { "version": "5.2.1", "funding": [ @@ -26351,30 +25763,6 @@ "node": ">=0.10.0" } }, - "print/node_modules/streamroller": { - "version": "3.1.5", - "license": "MIT", - "dependencies": { - "date-format": "^4.0.14", - "debug": "^4.3.4", - "fs-extra": "^8.1.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "print/node_modules/streamroller/node_modules/fs-extra": { - "version": "8.1.0", - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, "print/node_modules/strftime": { "version": "0.10.1", "license": "MIT", @@ -26431,37 +25819,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "print/node_modules/tar-fs": { - "version": "2.1.1", - "license": "MIT", - "peer": true, - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "print/node_modules/tar-stream": { - "version": "2.2.0", - "license": "MIT", - "peer": true, - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "print/node_modules/through": { - "version": "2.3.8", - "license": "MIT", - "peer": true - }, "print/node_modules/tough-cookie": { "version": "2.5.0", "license": "BSD-3-Clause", @@ -26473,11 +25830,6 @@ "node": ">=0.8" } }, - "print/node_modules/tr46": { - "version": "0.0.3", - "license": "MIT", - "peer": true - }, "print/node_modules/tunnel-agent": { "version": "0.6.0", "license": "Apache-2.0", @@ -26492,15 +25844,6 @@ "version": "0.14.5", "license": "Unlicense" }, - "print/node_modules/unbzip2-stream": { - "version": "1.4.3", - "license": "MIT", - "peer": true, - "dependencies": { - "buffer": "^5.2.1", - "through": "^2.3.8" - } - }, "print/node_modules/universalify": { "version": "0.1.2", "license": "MIT", @@ -26744,20 +26087,6 @@ "entities": "^2.0.0" } }, - "print/node_modules/webidl-conversions": { - "version": "3.0.1", - "license": "BSD-2-Clause", - "peer": true - }, - "print/node_modules/whatwg-url": { - "version": "5.0.0", - "license": "MIT", - "peer": true, - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "print/node_modules/which": { "version": "1.3.1", "license": "ISC", @@ -26811,38 +26140,6 @@ "version": "1.1.4", "license": "MIT" }, - "print/node_modules/wrappy": { - "version": "1.0.2", - "license": "ISC", - "peer": true - }, - "print/node_modules/ws": { - "version": "8.11.0", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "print/node_modules/xmldom": { - "version": "0.6.0", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - } - }, "print/node_modules/xtend": { "version": "4.0.2", "license": "MIT", @@ -26888,15 +26185,6 @@ "engines": { "node": ">=6" } - }, - "print/node_modules/yauzl": { - "version": "2.10.0", - "license": "MIT", - "peer": true, - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } } }, "dependencies": { @@ -28794,6 +28082,8 @@ }, "@types/yauzl": { "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", "optional": true, "requires": { "@types/node": "*" @@ -29239,6 +28529,16 @@ } } }, + "array-parallel": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/array-parallel/-/array-parallel-0.1.3.tgz", + "integrity": "sha512-TDPTwSWW5E4oiFiKmz6RGJ/a80Y91GuLgUYuLd49+XBS75tYo8PNgaT2K/OxuQYqkoI852MDGBorg9OcUSTQ8w==" + }, + "array-series": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/array-series/-/array-series-0.1.5.tgz", + "integrity": "sha512-L0XlBwfx9QetHOsbLDrE/vh2t018w9462HM3iaFfxRiK83aJjAt/Ja3NMkOW7FICwWTlQBa3ZbL5FKhuQWkDrg==" + }, "array-slice": { "version": "1.1.0", "dev": true @@ -29422,6 +28722,8 @@ }, "axios": { "version": "1.2.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.2.tgz", + "integrity": "sha512-bz/J4gS2S3I7mpN/YZfGFTqhXTYzRho8Ay38w2otuuDR322KzFIWm/4W2K6gIwvWaws5n+mnb7D1lN9uD+QH6Q==", "requires": { "follow-redirects": "^1.15.0", "form-data": "^4.0.0", @@ -29631,7 +28933,9 @@ "version": "1.0.2" }, "base64url": { - "version": "3.0.1" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", + "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==" }, "batch": { "version": "0.6.1", @@ -29972,7 +29276,9 @@ } }, "buffer-crc32": { - "version": "0.2.13" + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==" }, "buffer-equal": { "version": "1.0.0", @@ -30496,13 +29802,6 @@ "object-visit": "^1.0.0" } }, - "color": { - "version": "4.2.3", - "requires": { - "color-convert": "^2.0.1", - "color-string": "^1.9.0" - } - }, "color-convert": { "version": "2.0.1", "requires": { @@ -30512,13 +29811,6 @@ "color-name": { "version": "1.1.4" }, - "color-string": { - "version": "1.9.1", - "requires": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, "color-support": { "version": "1.1.3" }, @@ -30922,6 +30214,9 @@ "date-and-time": { "version": "0.6.3" }, + "date-format": { + "version": "4.0.14" + }, "dateformat": { "version": "2.2.0", "dev": true @@ -30962,7 +30257,8 @@ } }, "deep-extend": { - "version": "0.6.0" + "version": "0.6.0", + "dev": true }, "deep-is": { "version": "0.1.4" @@ -31178,7 +30474,9 @@ "dev": true }, "devtools-protocol": { - "version": "0.0.1045489" + "version": "0.0.1045489", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1045489.tgz", + "integrity": "sha512-D+PTmWulkuQW4D1NTiCRCFxF7pQPn0hgp4YyX4wAQ6xYXKOadSWPR3ENGDQ47MW/Ewc9v2rpC/UEEGahgBYpSQ==" }, "diff": { "version": "1.4.0" @@ -31974,9 +31272,6 @@ } } }, - "expand-template": { - "version": "2.0.3" - }, "expand-tilde": { "version": "2.0.2", "dev": true, @@ -32134,6 +31429,8 @@ }, "extract-zip": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", "requires": { "@types/yauzl": "^2.9.1", "debug": "^4.1.1", @@ -32143,12 +31440,16 @@ "dependencies": { "debug": { "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "requires": { "ms": "2.1.2" } }, "ms": { - "version": "2.1.2" + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" } } }, @@ -32214,6 +31515,8 @@ }, "fd-slicer": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", "requires": { "pend": "~1.2.0" } @@ -32496,8 +31799,7 @@ } }, "flatted": { - "version": "3.2.7", - "dev": true + "version": "3.2.7" }, "flush-write-stream": { "version": "1.1.1", @@ -32534,7 +31836,9 @@ } }, "follow-redirects": { - "version": "1.15.2" + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" }, "for-in": { "version": "1.0.2", @@ -32552,6 +31856,8 @@ }, "form-data": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -32851,9 +32157,6 @@ "assert-plus": "^1.0.0" } }, - "github-from-package": { - "version": "0.0.0" - }, "glob": { "version": "7.2.0", "requires": { @@ -33155,6 +32458,63 @@ "sparkles": "^1.0.0" } }, + "gm": { + "version": "1.25.0", + "resolved": "https://registry.npmjs.org/gm/-/gm-1.25.0.tgz", + "integrity": "sha512-4kKdWXTtgQ4biIo7hZA396HT062nDVVHPjQcurNZ3o/voYN+o5FUC5kOwuORbpExp3XbTJ3SU7iRipiIhQtovw==", + "requires": { + "array-parallel": "~0.1.3", + "array-series": "~0.1.5", + "cross-spawn": "^4.0.0", + "debug": "^3.1.0" + }, + "dependencies": { + "cross-spawn": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", + "integrity": "sha512-yAXz/pA1tD8Gtg2S98Ekf/sewp3Lcp3YoFKJ4Hkp5h5yLWnKVTDU0kwjKJ8NDCYcfTLfyGkzTikst+jWypT1iA==", + "requires": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==" + } + } + }, "google-auth-library": { "version": "3.1.2", "requires": { @@ -34701,7 +34061,8 @@ "version": "2.0.4" }, "ini": { - "version": "1.3.8" + "version": "1.3.8", + "dev": true }, "internal-ip": { "version": "4.3.0", @@ -34777,9 +34138,6 @@ "has-tostringtag": "^1.0.0" } }, - "is-arrayish": { - "version": "0.3.2" - }, "is-bigint": { "version": "1.0.4", "dev": true, @@ -35169,6 +34527,8 @@ }, "jasmine": { "version": "4.5.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-4.5.0.tgz", + "integrity": "sha512-9olGRvNZyADIwYL9XBNBst5BTU/YaePzuddK+YRslc7rI9MdTIE4r3xaBKbv2GEmzYYUfMOdTR8/i6JfLZaxSQ==", "dev": true, "requires": { "glob": "^7.1.6", @@ -35177,6 +34537,8 @@ }, "jasmine-core": { "version": "4.5.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.5.0.tgz", + "integrity": "sha512-9PMzyvhtocxb3aXJVOPqBDswdgyAeSB81QnLop4npOpbqnheaTEwPc9ZloQeVswugPManznQBjD8kWDTjlnHuw==", "dev": true }, "jasmine-reporters": { @@ -35822,6 +35184,11 @@ "xmlcreate": "^1.0.1" } }, + "jsbarcode": { + "version": "3.11.5", + "resolved": "https://registry.npmjs.org/jsbarcode/-/jsbarcode-3.11.5.tgz", + "integrity": "sha512-zv3KsH51zD00I/LrFzFSM6dst7rDn0vIMzaiZFL7qusTjPZiPtxg3zxetp0RR7obmjTw4f6NyGgbdkBCgZUIrA==" + }, "jsbn": { "version": "0.1.1" }, @@ -36361,6 +35728,27 @@ "version": "4.4.2", "dev": true }, + "log4js": { + "version": "6.7.0", + "requires": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "flatted": "^3.2.7", + "rfdc": "^1.3.0", + "streamroller": "^3.1.3" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2" + } + } + }, "loglevel": { "version": "1.8.0", "dev": true @@ -37526,9 +36914,6 @@ "to-regex": "^3.0.1" } }, - "napi-build-utils": { - "version": "1.0.2" - }, "natural-compare": { "version": "1.4.0", "dev": true @@ -37557,29 +36942,6 @@ "nocache": { "version": "2.1.0" }, - "node-abi": { - "version": "3.28.0", - "requires": { - "semver": "^7.3.5" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "requires": { - "yallist": "^4.0.0" - } - }, - "semver": { - "version": "7.3.8", - "requires": { - "lru-cache": "^6.0.0" - } - }, - "yallist": { - "version": "4.0.0" - } - } - }, "node-addon-api": { "version": "5.0.0" }, @@ -38638,7 +38000,9 @@ } }, "pend": { - "version": "1.2.0" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==" }, "performance-now": { "version": "2.1.0" @@ -38812,23 +38176,6 @@ "version": "3.3.1", "dev": true }, - "prebuild-install": { - "version": "7.1.1", - "requires": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - } - }, "precond": { "version": "0.2.3" }, @@ -38902,7 +38249,9 @@ } }, "proxy-from-env": { - "version": "1.1.0" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, "prr": { "version": "1.0.1", @@ -38972,6 +38321,8 @@ }, "puppeteer": { "version": "18.2.1", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-18.2.1.tgz", + "integrity": "sha512-7+UhmYa7wxPh2oMRwA++k8UGVDxh3YdWFB52r9C3tM81T6BU7cuusUSxImz0GEYSOYUKk/YzIhkQ6+vc0gHbxQ==", "requires": { "https-proxy-agent": "5.0.1", "progress": "2.0.3", @@ -39003,8 +38354,27 @@ } } }, + "puppeteer-cluster": { + "version": "0.23.0", + "requires": { + "debug": "^4.3.3" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2" + } + } + }, "puppeteer-core": { "version": "18.2.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-18.2.1.tgz", + "integrity": "sha512-MRtTAZfQTluz3U2oU/X2VqVWPcR1+94nbA2V6ZrSZRVEwLqZ8eclZ551qGFQD/vD2PYqHJwWOW/fpC721uznVw==", "requires": { "cross-fetch": "3.1.5", "debug": "4.3.4", @@ -39020,28 +38390,38 @@ "dependencies": { "agent-base": { "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "requires": { "debug": "4" } }, "debug": { "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "requires": { "ms": "2.1.2" } }, "https-proxy-agent": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", "requires": { "agent-base": "6", "debug": "4" } }, "ms": { - "version": "2.1.2" + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "ws": { "version": "8.9.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.9.0.tgz", + "integrity": "sha512-Ja7nszREasGaYUYCI2k4lCKIRTt+y7XuqVoHR44YpI49TtryyqbqvDMn5eqfW7e6HzTukDRIsXqzVHScqRcafg==", "requires": {} } } @@ -39129,6 +38509,7 @@ }, "rc": { "version": "1.2.8", + "dev": true, "requires": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -39626,6 +39007,8 @@ "dependencies": { "form-data": { "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", @@ -39730,6 +39113,9 @@ } } }, + "rfdc": { + "version": "1.3.0" + }, "rimraf": { "version": "3.0.2", "requires": { @@ -40336,36 +39722,6 @@ "kind-of": "^6.0.2" } }, - "sharp": { - "version": "0.31.3", - "requires": { - "color": "^4.2.3", - "detect-libc": "^2.0.1", - "node-addon-api": "^5.0.0", - "prebuild-install": "^7.1.1", - "semver": "^7.3.8", - "simple-get": "^4.0.1", - "tar-fs": "^2.1.1", - "tunnel-agent": "^0.6.0" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "requires": { - "yallist": "^4.0.0" - } - }, - "semver": { - "version": "7.3.8", - "requires": { - "lru-cache": "^6.0.0" - } - }, - "yallist": { - "version": "4.0.0" - } - } - }, "shebang-command": { "version": "2.0.0", "requires": { @@ -40406,34 +39762,6 @@ "signal-exit": { "version": "3.0.7" }, - "simple-concat": { - "version": "1.0.1" - }, - "simple-get": { - "version": "4.0.1", - "requires": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - }, - "dependencies": { - "decompress-response": { - "version": "6.0.0", - "requires": { - "mimic-response": "^3.1.0" - } - }, - "mimic-response": { - "version": "3.1.0" - } - } - }, - "simple-swizzle": { - "version": "0.2.2", - "requires": { - "is-arrayish": "^0.3.1" - } - }, "simple-update-notifier": { "version": "1.0.7", "dev": true, @@ -40981,6 +40309,33 @@ "stream-shift": { "version": "1.0.1" }, + "streamroller": { + "version": "3.1.3", + "requires": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "requires": { + "ms": "2.1.2" + } + }, + "fs-extra": { + "version": "8.1.0", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "ms": { + "version": "2.1.2" + } + } + }, "streamsearch": { "version": "0.1.2" }, @@ -41052,7 +40407,8 @@ } }, "strip-json-comments": { - "version": "2.0.1" + "version": "2.0.1", + "dev": true }, "strong-error-handler": { "version": "2.3.2", @@ -42051,16 +41407,22 @@ }, "unbzip2-stream": { "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", "requires": { "buffer": "^5.2.1", "through": "^2.3.8" }, "dependencies": { "base64-js": { - "version": "1.5.1" + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, "buffer": { "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "requires": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -42608,42 +41970,9 @@ "xmldom": "^0.6.0" }, "dependencies": { - "@babel/code-frame": { - "version": "7.18.6", - "peer": true, - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "peer": true - }, - "@babel/highlight": { - "version": "7.18.6", - "peer": true, - "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, "@babel/parser": { "version": "7.19.3" }, - "@types/node": { - "version": "18.14.2", - "optional": true, - "peer": true - }, - "@types/yauzl": { - "version": "2.10.0", - "optional": true, - "peer": true, - "requires": { - "@types/node": "*" - } - }, "@vue/compiler-sfc": { "version": "2.7.10", "requires": { @@ -42652,13 +41981,6 @@ "source-map": "^0.6.1" } }, - "agent-base": { - "version": "6.0.2", - "peer": true, - "requires": { - "debug": "4" - } - }, "ajv": { "version": "6.12.6", "requires": { @@ -42704,56 +42026,15 @@ "aws4": { "version": "1.11.0" }, - "balanced-match": { - "version": "1.0.2", - "peer": true - }, - "base64-js": { - "version": "1.5.1", - "peer": true - }, "bcrypt-pbkdf": { "version": "1.0.2", "requires": { "tweetnacl": "^0.14.3" } }, - "bl": { - "version": "4.1.0", - "peer": true, - "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, "boolbase": { "version": "1.0.0" }, - "brace-expansion": { - "version": "1.1.11", - "peer": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "buffer": { - "version": "5.7.1", - "peer": true, - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "buffer-crc32": { - "version": "0.2.13", - "peer": true - }, - "callsites": { - "version": "3.1.0", - "peer": true - }, "camelcase": { "version": "5.3.1" }, @@ -42789,17 +42070,6 @@ "lodash.some": "^4.4.0" } }, - "chownr": { - "version": "1.1.4", - "peer": true - }, - "chromium-bidi": { - "version": "0.4.4", - "peer": true, - "requires": { - "mitt": "3.0.0" - } - }, "cliui": { "version": "6.0.0", "requires": { @@ -42826,43 +42096,9 @@ "commander": { "version": "2.20.3" }, - "concat-map": { - "version": "0.0.1", - "peer": true - }, "core-util-is": { "version": "1.0.2" }, - "cosmiconfig": { - "version": "8.0.0", - "peer": true, - "requires": { - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0" - }, - "dependencies": { - "argparse": { - "version": "2.0.1", - "peer": true - }, - "js-yaml": { - "version": "4.1.0", - "peer": true, - "requires": { - "argparse": "^2.0.1" - } - } - } - }, - "cross-fetch": { - "version": "3.1.5", - "peer": true, - "requires": { - "node-fetch": "2.6.7" - } - }, "cross-spawn": { "version": "6.0.5", "requires": { @@ -42901,15 +42137,6 @@ "mimer": "^1.0.0" } }, - "date-format": { - "version": "4.0.14" - }, - "debug": { - "version": "4.3.4", - "requires": { - "ms": "2.1.2" - } - }, "decamelize": { "version": "1.2.0" }, @@ -42922,10 +42149,6 @@ "denque": { "version": "1.5.1" }, - "devtools-protocol": { - "version": "0.0.1094867", - "peer": true - }, "dijkstrajs": { "version": "1.0.2" }, @@ -42965,23 +42188,9 @@ "encode-utf8": { "version": "1.0.3" }, - "end-of-stream": { - "version": "1.4.4", - "peer": true, - "requires": { - "once": "^1.4.0" - } - }, "entities": { "version": "1.1.2" }, - "error-ex": { - "version": "1.3.2", - "peer": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, "escape-string-regexp": { "version": "1.0.5" }, @@ -42991,16 +42200,6 @@ "extend": { "version": "3.0.2" }, - "extract-zip": { - "version": "2.0.1", - "peer": true, - "requires": { - "@types/yauzl": "^2.9.1", - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - } - }, "extsprintf": { "version": "1.3.0" }, @@ -43010,13 +42209,6 @@ "fast-json-stable-stringify": { "version": "2.1.0" }, - "fd-slicer": { - "version": "1.1.0", - "peer": true, - "requires": { - "pend": "~1.2.0" - } - }, "find-up": { "version": "4.1.0", "requires": { @@ -43024,9 +42216,6 @@ "path-exists": "^4.0.0" } }, - "flatted": { - "version": "3.2.7" - }, "forever-agent": { "version": "0.6.1" }, @@ -43038,10 +42227,6 @@ "mime-types": "^2.1.12" } }, - "fs-constants": { - "version": "1.0.0", - "peer": true - }, "fs-extra": { "version": "7.0.1", "requires": { @@ -43050,10 +42235,6 @@ "universalify": "^0.1.0" } }, - "fs.realpath": { - "version": "1.0.0", - "peer": true - }, "function-bind": { "version": "1.1.1" }, @@ -43066,31 +42247,12 @@ "get-caller-file": { "version": "2.0.5" }, - "get-stream": { - "version": "5.2.0", - "peer": true, - "requires": { - "pump": "^3.0.0" - } - }, "getpass": { "version": "0.1.7", "requires": { "assert-plus": "^1.0.0" } }, - "glob": { - "version": "7.2.3", - "peer": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, "graceful-fs": { "version": "4.2.10" }, @@ -43138,53 +42300,21 @@ "sshpk": "^1.7.0" } }, - "https-proxy-agent": { - "version": "5.0.1", - "peer": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, "iconv-lite": { "version": "0.5.2", "requires": { "safer-buffer": ">= 2.1.2 < 3" } }, - "ieee754": { - "version": "1.2.1", - "peer": true - }, "image-size": { "version": "0.7.5" }, - "import-fresh": { - "version": "3.3.0", - "peer": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "inflight": { - "version": "1.0.6", - "peer": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "inherits": { "version": "2.0.4" }, "intl": { "version": "1.2.5" }, - "is-arrayish": { - "version": "0.2.1", - "peer": true - }, "is-core-module": { "version": "2.10.0", "requires": { @@ -43206,10 +42336,6 @@ "isstream": { "version": "0.1.2" }, - "js-tokens": { - "version": "4.0.0", - "peer": true - }, "js-yaml": { "version": "3.14.1", "requires": { @@ -43217,16 +42343,9 @@ "esprima": "^4.0.0" } }, - "jsbarcode": { - "version": "3.11.5" - }, "jsbn": { "version": "0.1.1" }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "peer": true - }, "json-schema": { "version": "0.4.0" }, @@ -43266,10 +42385,6 @@ "web-resource-inliner": "^4.3.1" } }, - "lines-and-columns": { - "version": "1.2.4", - "peer": true - }, "locate-path": { "version": "5.0.0", "requires": { @@ -43334,16 +42449,6 @@ "lodash.uniq": { "version": "4.5.0" }, - "log4js": { - "version": "6.8.0", - "requires": { - "date-format": "^4.0.14", - "debug": "^4.3.4", - "flatted": "^3.2.7", - "rfdc": "^1.3.0", - "streamroller": "^3.1.5" - } - }, "long": { "version": "4.0.0" }, @@ -43368,24 +42473,6 @@ "mimer": { "version": "1.1.1" }, - "minimatch": { - "version": "3.1.2", - "peer": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "mitt": { - "version": "3.0.0", - "peer": true - }, - "mkdirp-classic": { - "version": "0.5.3", - "peer": true - }, - "ms": { - "version": "2.1.2" - }, "mysql2": { "version": "1.7.0", "requires": { @@ -43423,13 +42510,6 @@ "nice-try": { "version": "1.0.5" }, - "node-fetch": { - "version": "2.6.7", - "peer": true, - "requires": { - "whatwg-url": "^5.0.0" - } - }, "nodemailer": { "version": "4.7.0" }, @@ -43442,13 +42522,6 @@ "oauth-sign": { "version": "0.9.0" }, - "once": { - "version": "1.4.0", - "peer": true, - "requires": { - "wrappy": "1" - } - }, "p-limit": { "version": "2.3.0", "requires": { @@ -43464,44 +42537,15 @@ "p-try": { "version": "2.2.0" }, - "parent-module": { - "version": "1.0.1", - "peer": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-json": { - "version": "5.2.0", - "peer": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, "path-exists": { "version": "4.0.0" }, - "path-is-absolute": { - "version": "1.0.1", - "peer": true - }, "path-key": { "version": "2.0.1" }, "path-parse": { "version": "1.0.7" }, - "path-type": { - "version": "4.0.0", - "peer": true - }, - "pend": { - "version": "1.2.0", - "peer": true - }, "performance-now": { "version": "2.1.0" }, @@ -43519,65 +42563,15 @@ "source-map-js": "^1.0.2" } }, - "progress": { - "version": "2.0.3", - "peer": true - }, - "proxy-from-env": { - "version": "1.1.0", - "peer": true - }, "pseudomap": { "version": "1.0.2" }, "psl": { "version": "1.9.0" }, - "pump": { - "version": "3.0.0", - "peer": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "punycode": { "version": "2.1.1" }, - "puppeteer": { - "version": "19.7.2", - "peer": true, - "requires": { - "cosmiconfig": "8.0.0", - "https-proxy-agent": "5.0.1", - "progress": "2.0.3", - "proxy-from-env": "1.1.0", - "puppeteer-core": "19.7.2" - } - }, - "puppeteer-cluster": { - "version": "0.23.0", - "requires": { - "debug": "^4.3.3" - } - }, - "puppeteer-core": { - "version": "19.7.2", - "peer": true, - "requires": { - "chromium-bidi": "0.4.4", - "cross-fetch": "3.1.5", - "debug": "4.3.4", - "devtools-protocol": "0.0.1094867", - "extract-zip": "2.0.1", - "https-proxy-agent": "5.0.1", - "proxy-from-env": "1.1.0", - "rimraf": "3.0.2", - "tar-fs": "2.1.1", - "unbzip2-stream": "1.4.3", - "ws": "8.11.0" - } - }, "qrcode": { "version": "1.5.1", "requires": { @@ -43643,20 +42637,6 @@ "supports-preserve-symlinks-flag": "^1.0.0" } }, - "resolve-from": { - "version": "4.0.0", - "peer": true - }, - "rfdc": { - "version": "1.3.0" - }, - "rimraf": { - "version": "3.0.2", - "peer": true, - "requires": { - "glob": "^7.1.3" - } - }, "safe-buffer": { "version": "5.2.1" }, @@ -43716,24 +42696,6 @@ "tweetnacl": "~0.14.0" } }, - "streamroller": { - "version": "3.1.5", - "requires": { - "date-format": "^4.0.14", - "debug": "^4.3.4", - "fs-extra": "^8.1.0" - }, - "dependencies": { - "fs-extra": { - "version": "8.1.0", - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - } - } - }, "strftime": { "version": "0.10.1" }, @@ -43766,31 +42728,6 @@ "supports-preserve-symlinks-flag": { "version": "1.0.0" }, - "tar-fs": { - "version": "2.1.1", - "peer": true, - "requires": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "tar-stream": { - "version": "2.2.0", - "peer": true, - "requires": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - } - }, - "through": { - "version": "2.3.8", - "peer": true - }, "tough-cookie": { "version": "2.5.0", "requires": { @@ -43798,10 +42735,6 @@ "punycode": "^2.1.1" } }, - "tr46": { - "version": "0.0.3", - "peer": true - }, "tunnel-agent": { "version": "0.6.0", "requires": { @@ -43811,14 +42744,6 @@ "tweetnacl": { "version": "0.14.5" }, - "unbzip2-stream": { - "version": "1.4.3", - "peer": true, - "requires": { - "buffer": "^5.2.1", - "through": "^2.3.8" - } - }, "universalify": { "version": "0.1.2" }, @@ -43973,18 +42898,6 @@ } } }, - "webidl-conversions": { - "version": "3.0.1", - "peer": true - }, - "whatwg-url": { - "version": "5.0.0", - "peer": true, - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "which": { "version": "1.3.1", "requires": { @@ -44019,18 +42932,6 @@ } } }, - "wrappy": { - "version": "1.0.2", - "peer": true - }, - "ws": { - "version": "8.11.0", - "peer": true, - "requires": {} - }, - "xmldom": { - "version": "0.6.0" - }, "xtend": { "version": "4.0.2" }, @@ -44062,14 +42963,6 @@ "camelcase": "^5.0.0", "decamelize": "^1.2.0" } - }, - "yauzl": { - "version": "2.10.0", - "peer": true, - "requires": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } } } }, @@ -45128,6 +44021,11 @@ "xmlcreate": { "version": "1.0.2" }, + "xmldom": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.6.0.tgz", + "integrity": "sha512-iAcin401y58LckRZ0TkI4k0VSM1Qg0KGSc3i8rU+xrxe19A/BN1zHyVSJY7uoutVlaTSzYyk/v5AmkewAP7jtg==" + }, "xtend": { "version": "1.0.3" }, @@ -45215,6 +44113,8 @@ }, "yauzl": { "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", "requires": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" diff --git a/package.json b/package.json index 30c8039ac..8d6c5340b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "salix-back", - "version": "23.10.01", + "version": "23.16.01", "author": "Verdnatura Levante SL", "description": "Salix backend", "license": "GPL-3.0", @@ -20,6 +20,7 @@ "form-data": "^4.0.0", "fs-extra": "^5.0.0", "ftps": "^1.2.0", + "gm": "^1.25.0", "got": "^10.7.0", "helmet": "^3.21.2", "i18n": "^0.8.4", @@ -43,7 +44,6 @@ "puppeteer": "^18.0.5", "read-chunk": "^3.2.0", "require-yaml": "0.0.1", - "sharp": "^0.31.3", "smbhash": "0.0.1", "strong-error-handler": "^2.3.2", "uuid": "^3.3.3", diff --git a/print/core/cluster.js b/print/core/cluster.js index 23b3d88e9..d54044fa2 100644 --- a/print/core/cluster.js +++ b/print/core/cluster.js @@ -4,40 +4,38 @@ const {cpus} = require('os'); module.exports = { init() { - if (!this.pool) { - Cluster.launch({ - concurrency: Cluster.CONCURRENCY_CONTEXT, - maxConcurrency: cpus().length, - puppeteerOptions: { - headless: true, - args: [ - '--no-sandbox', - '--disable-setuid-sandbox', - '--no-zygote' - ] - } - }) - .then(cluster => { - this.pool = cluster; + if (this.pool) return; + Cluster.launch({ + concurrency: Cluster.CONCURRENCY_CONTEXT, + maxConcurrency: cpus().length, + puppeteerOptions: { + headless: true, + args: [ + '--no-sandbox', + '--disable-setuid-sandbox', + '--no-zygote' + ] + } + }).then(cluster => { + this.pool = cluster; - log4js.configure({ - appenders: { - out: {type: 'stdout'} - }, - categories: {default: {appenders: ['out'], level: 'info'}}, - }); + log4js.configure({ + appenders: { + out: {type: 'stdout'} + }, + categories: {default: {appenders: ['out'], level: 'info'}}, + }); - const logger = log4js.getLogger(); + const logger = log4js.getLogger(); - cluster.on('taskerror', (err, data, willRetry) => { - if (willRetry) - logger.warn(`[Print] => ${err.message}\nThis job will be retried`); - else - logger.error(`[Print] => ${err.message}`); - }); + cluster.on('taskerror', (err, data, willRetry) => { + if (willRetry) + logger.warn(`[Print] => ${err.message}\nThis job will be retried`); + else + logger.error(`[Print] => ${err.message}`); + }); - cluster.on('queue', () => logger.info('Printing task initialized by pool')); - }); - } + cluster.on('queue', () => logger.info('Printing task initialized by pool')); + }); } }; diff --git a/print/core/report.js b/print/core/report.js index c5182d1a8..23cffac2c 100644 --- a/print/core/report.js +++ b/print/core/report.js @@ -32,28 +32,31 @@ class Report extends Component { if (fs.existsSync(fullPath)) options = require(optionsPath); - return new Promise(resolve => { + return new Promise((resolve, reject) => { Cluster.pool.queue({}, async({page}) => { - await page.emulateMediaType('screen'); - await page.setContent(template); + try { + await page.emulateMediaType('screen'); + await page.setContent(template); - const element = await page.$('#pageFooter'); + const element = await page.$('#pageFooter'); - let footer = '\n'; - if (element) { - footer = await page.evaluate(el => { - const html = el.innerHTML; - el.remove(); - return html; - }, element); + let footer = '\n'; + if (element) { + footer = await page.evaluate(el => { + const html = el.innerHTML; + el.remove(); + return html; + }, element); + } + + options.headerTemplate = '\n'; + options.footerTemplate = footer; + + const buffer = await page.pdf(options); + resolve(buffer); + } catch (err) { + reject(err); } - - options.headerTemplate = '\n'; - options.footerTemplate = footer; - - const stream = await page.pdf(options); - - resolve(stream); }); }); } diff --git a/print/core/storage.js b/print/core/storage.js index 063a2fbec..66f7ce98a 100644 --- a/print/core/storage.js +++ b/print/core/storage.js @@ -3,26 +3,14 @@ const path = require('path'); const fs = require('fs-extra'); module.exports = { - async write(stream, options) { + async write(buffer, options) { const storage = config.storage[options.type]; - if (!storage) return; const src = path.join(storage.root, options.path); const fileSrc = path.join(src, options.fileName); await fs.mkdir(src, {recursive: true}); - - const writeStream = fs.createWriteStream(fileSrc); - writeStream.on('open', () => writeStream.write(stream)); - writeStream.on('finish', () => writeStream.end()); - - return new Promise(resolve => { - writeStream.on('close', () => resolve()); - }); - }, - - load(type, data) { - + await fs.writeFile(fileSrc, buffer); } }; diff --git a/print/package-lock.json b/print/package-lock.json deleted file mode 100644 index b8fd28928..000000000 --- a/print/package-lock.json +++ /dev/null @@ -1,4682 +0,0 @@ -{ - "name": "vn-print", - "version": "2.0.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "vn-print", - "version": "2.0.0", - "license": "GPL-3.0", - "dependencies": { - "fs-extra": "^7.0.1", - "intl": "^1.2.5", - "js-yaml": "^3.13.1", - "jsbarcode": "^3.11.5", - "jsonexport": "^3.2.0", - "juice": "^5.2.0", - "log4js": "^6.7.0", - "mysql2": "^1.7.0", - "nodemailer": "^4.7.0", - "puppeteer-cluster": "^0.23.0", - "qrcode": "^1.4.2", - "strftime": "^0.10.0", - "vue": "^2.6.10", - "vue-i18n": "^8.15.0", - "vue-server-renderer": "^2.6.10", - "xmldom": "^0.6.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "peer": true, - "dependencies": { - "@babel/highlight": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "peer": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.3.tgz", - "integrity": "sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ==", - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@types/node": { - "version": "18.14.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.2.tgz", - "integrity": "sha512-1uEQxww3DaghA0RxqHx0O0ppVlo43pJhepY51OxuQIKHpjbnYLA7vcdwioNPzIqmC2u3I/dmylcqjlh0e7AyUA==", - "optional": true, - "peer": true - }, - "node_modules/@types/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", - "optional": true, - "peer": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@vue/compiler-sfc": { - "version": "2.7.10", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-2.7.10.tgz", - "integrity": "sha512-55Shns6WPxlYsz4WX7q9ZJBL77sKE1ZAYNYStLs6GbhIOMrNtjMvzcob6gu3cGlfpCR4bT7NXgyJ3tly2+Hx8Q==", - "dependencies": { - "@babel/parser": "^7.18.4", - "postcss": "^8.4.14", - "source-map": "^0.6.1" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "peer": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/async": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", - "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", - "engines": { - "node": "*" - } - }, - "node_modules/aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "peer": true - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "peer": true - }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "peer": true, - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "peer": true, - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "peer": true, - "engines": { - "node": "*" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cheerio": { - "version": "0.22.0", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz", - "integrity": "sha512-8/MzidM6G/TgRelkzDG13y3Y9LxBjCb+8yOEZ9+wwq5gVF2w2pV0wmHvjfT0RvuxGyR7UEuK36r+yYMbT4uKgA==", - "dependencies": { - "css-select": "~1.2.0", - "dom-serializer": "~0.1.0", - "entities": "~1.1.1", - "htmlparser2": "^3.9.1", - "lodash.assignin": "^4.0.9", - "lodash.bind": "^4.1.4", - "lodash.defaults": "^4.0.1", - "lodash.filter": "^4.4.0", - "lodash.flatten": "^4.2.0", - "lodash.foreach": "^4.3.0", - "lodash.map": "^4.4.0", - "lodash.merge": "^4.4.0", - "lodash.pick": "^4.2.1", - "lodash.reduce": "^4.4.0", - "lodash.reject": "^4.4.0", - "lodash.some": "^4.4.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "peer": true - }, - "node_modules/chromium-bidi": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.4.tgz", - "integrity": "sha512-4BX5cSaponuvVT1+SbLYTOAgDoVtX/Khoc9UsbFJ/AsPVUeFAM3RiIDFI6XFhLYMi9WmVJqh1ZH+dRpNKkKwiQ==", - "peer": true, - "dependencies": { - "mitt": "3.0.0" - }, - "peerDependencies": { - "devtools-protocol": "*" - } - }, - "node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "peer": true - }, - "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" - }, - "node_modules/cosmiconfig": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.0.0.tgz", - "integrity": "sha512-da1EafcpH6b/TD8vDRaWV7xFINlHlF6zKsGwS1TsuVJTZRkquaS5HTMq7uq6h31619QjbsYl21gVDOm32KM1vQ==", - "peer": true, - "dependencies": { - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/cosmiconfig/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==", - "peer": true - }, - "node_modules/cosmiconfig/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==", - "peer": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/cross-fetch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", - "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", - "peer": true, - "dependencies": { - "node-fetch": "2.6.7" - } - }, - "node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "engines": { - "node": ">=4.8" - } - }, - "node_modules/css-select": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", - "integrity": "sha512-dUQOBoqdR7QwV90WysXPLXG5LO7nhYBgiWVfxF80DKPF8zx1t/pUd2FYy73emg3zrjtM6dzmYgbHKfV2rxiHQA==", - "dependencies": { - "boolbase": "~1.0.0", - "css-what": "2.1", - "domutils": "1.5.1", - "nth-check": "~1.0.1" - } - }, - "node_modules/css-what": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", - "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==", - "engines": { - "node": "*" - } - }, - "node_modules/csstype": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", - "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" - }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/datauri": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/datauri/-/datauri-2.0.0.tgz", - "integrity": "sha512-zS2HSf9pI5XPlNZgIqJg/wCJpecgU/HA6E/uv2EfaWnW1EiTGLfy/EexTIsC9c99yoCOTXlqeeWk4FkCSuO3/g==", - "dependencies": { - "image-size": "^0.7.3", - "mimer": "^1.0.0" - }, - "engines": { - "node": ">= 4" - } - }, - "node_modules/date-format": { - "version": "4.0.14", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", - "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/denque": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", - "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/devtools-protocol": { - "version": "0.0.1094867", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1094867.tgz", - "integrity": "sha512-pmMDBKiRVjh0uKK6CT1WqZmM3hBVSgD+N2MrgyV1uNizAZMw4tx6i/RTc+/uCsKSCmg0xXx7arCP/OFcIwTsiQ==", - "peer": true - }, - "node_modules/dijkstrajs": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.2.tgz", - "integrity": "sha512-QV6PMaHTCNmKSeP6QoXhVTw9snc9VD8MulTT0Bd99Pacp4SS1cjcrYPgBPmibqKVtMJJfqC6XvOXgPMEEPH/fg==" - }, - "node_modules/dom-serializer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", - "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", - "dependencies": { - "domelementtype": "^1.3.0", - "entities": "^1.1.1" - } - }, - "node_modules/domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" - }, - "node_modules/domhandler": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", - "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", - "dependencies": { - "domelementtype": "1" - } - }, - "node_modules/domutils": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", - "integrity": "sha512-gSu5Oi/I+3wDENBsOWBiRK1eoGxcywYSqg3rR960/+EfY0CF4EX1VPkgHOZ3WiS/Jg2DtliF6BhWcHlfpYUcGw==", - "dependencies": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/encode-utf8": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/encode-utf8/-/encode-utf8-1.0.3.tgz", - "integrity": "sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==" - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "peer": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "peer": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "engines": { - "node": ">=0.8.0" - } - }, - "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==", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "node_modules/extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "peer": true, - "dependencies": { - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" - }, - "engines": { - "node": ">= 10.17.0" - }, - "optionalDependencies": { - "@types/yauzl": "^2.9.1" - } - }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", - "engines": [ - "node >=0.6.0" - ] - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "peer": true, - "dependencies": { - "pend": "~1.2.0" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==" - }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", - "engines": { - "node": "*" - } - }, - "node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "peer": true - }, - "node_modules/fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "peer": true - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/generate-function": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", - "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", - "dependencies": { - "is-property": "^1.0.2" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "peer": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "dependencies": { - "assert-plus": "^1.0.0" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "peer": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" - }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", - "engines": { - "node": ">=4" - } - }, - "node_modules/har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", - "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/hash-sum": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz", - "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==" - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "bin": { - "he": "bin/he" - } - }, - "node_modules/htmlparser2": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", - "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", - "dependencies": { - "domelementtype": "^1.3.1", - "domhandler": "^2.3.0", - "domutils": "^1.5.1", - "entities": "^1.1.1", - "inherits": "^2.0.1", - "readable-stream": "^3.1.1" - } - }, - "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - }, - "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "peer": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/iconv-lite": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.2.tgz", - "integrity": "sha512-kERHXvpSaB4aU3eANwidg79K8FlrN77m8G9V+0vOR3HYaRifrlwMEpT7ZBJqLSEIHnEgJTHcWK82wwLwwKwtag==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "peer": true - }, - "node_modules/image-size": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.7.5.tgz", - "integrity": "sha512-Hiyv+mXHfFEP7LzUL/llg9RwFxxY+o9N3JVLIeG5E7iFIFAalxvRU9UZthBdYDEVnzHMgjnKJPPpay5BWf1g9g==", - "bin": { - "image-size": "bin/image-size.js" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "peer": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "peer": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/intl": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/intl/-/intl-1.2.5.tgz", - "integrity": "sha512-rK0KcPHeBFBcqsErKSpvZnrOmWOj+EmDkyJ57e90YWaQNqbcivcqmKDlHEeNprDWOsKzPsh1BfSpPQdDvclHVw==" - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "peer": true - }, - "node_modules/is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==" - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "peer": true - }, - "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==", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsbarcode": { - "version": "3.11.5", - "resolved": "https://registry.npmjs.org/jsbarcode/-/jsbarcode-3.11.5.tgz", - "integrity": "sha512-zv3KsH51zD00I/LrFzFSM6dst7rDn0vIMzaiZFL7qusTjPZiPtxg3zxetp0RR7obmjTw4f6NyGgbdkBCgZUIrA==", - "bin": { - "auto.js": "bin/barcodes/CODE128/auto.js", - "Barcode.js": "bin/barcodes/Barcode.js", - "barcodes": "bin/barcodes", - "canvas.js": "bin/renderers/canvas.js", - "checksums.js": "bin/barcodes/MSI/checksums.js", - "codabar": "bin/barcodes/codabar", - "CODE128": "bin/barcodes/CODE128", - "CODE128_AUTO.js": "bin/barcodes/CODE128/CODE128_AUTO.js", - "CODE128.js": "bin/barcodes/CODE128/CODE128.js", - "CODE128A.js": "bin/barcodes/CODE128/CODE128A.js", - "CODE128B.js": "bin/barcodes/CODE128/CODE128B.js", - "CODE128C.js": "bin/barcodes/CODE128/CODE128C.js", - "CODE39": "bin/barcodes/CODE39", - "constants.js": "bin/barcodes/ITF/constants.js", - "defaults.js": "bin/options/defaults.js", - "EAN_UPC": "bin/barcodes/EAN_UPC", - "EAN.js": "bin/barcodes/EAN_UPC/EAN.js", - "EAN13.js": "bin/barcodes/EAN_UPC/EAN13.js", - "EAN2.js": "bin/barcodes/EAN_UPC/EAN2.js", - "EAN5.js": "bin/barcodes/EAN_UPC/EAN5.js", - "EAN8.js": "bin/barcodes/EAN_UPC/EAN8.js", - "encoder.js": "bin/barcodes/EAN_UPC/encoder.js", - "ErrorHandler.js": "bin/exceptions/ErrorHandler.js", - "exceptions": "bin/exceptions", - "exceptions.js": "bin/exceptions/exceptions.js", - "fixOptions.js": "bin/help/fixOptions.js", - "GenericBarcode": "bin/barcodes/GenericBarcode", - "getOptionsFromElement.js": "bin/help/getOptionsFromElement.js", - "getRenderProperties.js": "bin/help/getRenderProperties.js", - "help": "bin/help", - "index.js": "bin/renderers/index.js", - "index.tmp.js": "bin/barcodes/index.tmp.js", - "ITF": "bin/barcodes/ITF", - "ITF.js": "bin/barcodes/ITF/ITF.js", - "ITF14.js": "bin/barcodes/ITF/ITF14.js", - "JsBarcode.js": "bin/JsBarcode.js", - "linearizeEncodings.js": "bin/help/linearizeEncodings.js", - "merge.js": "bin/help/merge.js", - "MSI": "bin/barcodes/MSI", - "MSI.js": "bin/barcodes/MSI/MSI.js", - "MSI10.js": "bin/barcodes/MSI/MSI10.js", - "MSI1010.js": "bin/barcodes/MSI/MSI1010.js", - "MSI11.js": "bin/barcodes/MSI/MSI11.js", - "MSI1110.js": "bin/barcodes/MSI/MSI1110.js", - "object.js": "bin/renderers/object.js", - "options": "bin/options", - "optionsFromStrings.js": "bin/help/optionsFromStrings.js", - "pharmacode": "bin/barcodes/pharmacode", - "renderers": "bin/renderers", - "shared.js": "bin/renderers/shared.js", - "svg.js": "bin/renderers/svg.js", - "UPC.js": "bin/barcodes/EAN_UPC/UPC.js", - "UPCE.js": "bin/barcodes/EAN_UPC/UPCE.js" - } - }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "peer": true - }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" - }, - "node_modules/jsonexport": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonexport/-/jsonexport-3.2.0.tgz", - "integrity": "sha512-GbO9ugb0YTZatPd/hqCGR0FSwbr82H6OzG04yzdrG7XOe4QZ0jhQ+kOsB29zqkzoYJLmLxbbrFiuwbQu891XnQ==", - "bin": { - "jsonexport": "bin/jsonexport.js" - } - }, - "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/juice": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/juice/-/juice-5.2.0.tgz", - "integrity": "sha512-0l6GZmT3efexyaaay3SchKT5kG311N59TEFP5lfvEy0nz9SNqjx311plJ3b4jze7arsmDsiHQLh/xnAuk0HFTQ==", - "dependencies": { - "cheerio": "^0.22.0", - "commander": "^2.15.1", - "cross-spawn": "^6.0.5", - "deep-extend": "^0.6.0", - "mensch": "^0.3.3", - "slick": "^1.12.2", - "web-resource-inliner": "^4.3.1" - }, - "bin": { - "juice": "bin/juice" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "peer": true - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==" - }, - "node_modules/lodash.assignin": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz", - "integrity": "sha512-yX/rx6d/UTVh7sSVWVSIMjfnz95evAgDFdb1ZozC35I9mSFCkmzptOzevxjgbQUsc78NR44LVHWjsoMQXy9FDg==" - }, - "node_modules/lodash.bind": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz", - "integrity": "sha512-lxdsn7xxlCymgLYo1gGvVrfHmkjDiyqVv62FAeF2i5ta72BipE1SLxw8hPEPLhD4/247Ijw07UQH7Hq/chT5LA==" - }, - "node_modules/lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==" - }, - "node_modules/lodash.filter": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz", - "integrity": "sha512-pXYUy7PR8BCLwX5mgJ/aNtyOvuJTdZAo9EQFUvMIYugqmJxnrYaANvTbgndOzHSCSR0wnlBBfRXJL5SbWxo3FQ==" - }, - "node_modules/lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==" - }, - "node_modules/lodash.foreach": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", - "integrity": "sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ==" - }, - "node_modules/lodash.map": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", - "integrity": "sha512-worNHGKLDetmcEYDvh2stPCrrQRkP20E4l0iIS7F8EvzMqBBi7ltvFN5m1HvTf1P7Jk1txKhvFcmYsCr8O2F1Q==" - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" - }, - "node_modules/lodash.pick": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", - "integrity": "sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q==" - }, - "node_modules/lodash.reduce": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz", - "integrity": "sha512-6raRe2vxCYBhpBu+B+TtNGUzah+hQjVdu3E17wfusjyrXBka2nBS8OH/gjVZ5PvHOhWmIZTYri09Z6n/QfnNMw==" - }, - "node_modules/lodash.reject": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.reject/-/lodash.reject-4.6.0.tgz", - "integrity": "sha512-qkTuvgEzYdyhiJBx42YPzPo71R1aEr0z79kAv7Ixg8wPFEjgRgJdUsGMG3Hf3OYSF/kHI79XhNlt+5Ar6OzwxQ==" - }, - "node_modules/lodash.some": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz", - "integrity": "sha512-j7MJE+TuT51q9ggt4fSgVqro163BEFjAt3u97IqU+JA2DkWl80nFTrowzLpZ/BnpN7rrl0JA/593NAdd8p/scQ==" - }, - "node_modules/lodash.template": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", - "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", - "dependencies": { - "lodash._reinterpolate": "^3.0.0", - "lodash.templatesettings": "^4.0.0" - } - }, - "node_modules/lodash.templatesettings": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", - "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", - "dependencies": { - "lodash._reinterpolate": "^3.0.0" - } - }, - "node_modules/lodash.unescape": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz", - "integrity": "sha512-DhhGRshNS1aX6s5YdBE3njCCouPgnG29ebyHvImlZzXZf2SHgt+J08DHgytTPnpywNbO1Y8mNUFyQuIDBq2JZg==" - }, - "node_modules/lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" - }, - "node_modules/log4js": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.8.0.tgz", - "integrity": "sha512-g+V8gZyurIexrOvWQ+AcZsIvuK/lBnx2argejZxL4gVZ4Hq02kUYH6WZOnqxgBml+zzQZYdaEoTN84B6Hzm8Fg==", - "dependencies": { - "date-format": "^4.0.14", - "debug": "^4.3.4", - "flatted": "^3.2.7", - "rfdc": "^1.3.0", - "streamroller": "^3.1.5" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/mensch": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/mensch/-/mensch-0.3.4.tgz", - "integrity": "sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g==" - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/mimer/-/mimer-1.1.1.tgz", - "integrity": "sha512-ye7CWOnSgiX3mqOLJ0bNGxRAULS5a/gzjj6lGSCnRTkbLUhNvt/7dI80b6GZRoaj4CsylcWQzyyKKh1a3CT74g==", - "bin": { - "mimer": "bin/mimer" - }, - "engines": { - "node": ">= 6.0" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "peer": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/mitt": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.0.tgz", - "integrity": "sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==", - "peer": true - }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "peer": true - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/mysql2": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-1.7.0.tgz", - "integrity": "sha512-xTWWQPjP5rcrceZQ7CSTKR/4XIDeH/cRkNH/uzvVGQ7W5c7EJ0dXeJUusk7OKhIoHj7uFKUxDVSCfLIl+jluog==", - "dependencies": { - "denque": "^1.4.1", - "generate-function": "^2.3.1", - "iconv-lite": "^0.5.0", - "long": "^4.0.0", - "lru-cache": "^5.1.1", - "named-placeholders": "^1.1.2", - "seq-queue": "^0.0.5", - "sqlstring": "^2.3.1" - }, - "engines": { - "node": ">= 8.0" - } - }, - "node_modules/named-placeholders": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.2.tgz", - "integrity": "sha512-wiFWqxoLL3PGVReSZpjLVxyJ1bRqe+KKJVbr4hGs1KWfTZTQyezHFBbuKj9hsizHyGV2ne7EMjHdxEGAybD5SA==", - "dependencies": { - "lru-cache": "^4.1.3" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/named-placeholders/node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "node_modules/named-placeholders/node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==" - }, - "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" - }, - "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "peer": true, - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/nodemailer": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-4.7.0.tgz", - "integrity": "sha512-IludxDypFpYw4xpzKdMAozBSkzKHmNBvGanUREjJItgJ2NYcK/s8+PggVhj7c2yGFQykKsnnmv1+Aqo0ZfjHmw==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/nth-check": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", - "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", - "dependencies": { - "boolbase": "~1.0.0" - } - }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "engines": { - "node": "*" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "peer": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "peer": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "peer": true - }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "node_modules/pngjs": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", - "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/postcss": { - "version": "8.4.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.17.tgz", - "integrity": "sha512-UNxNOLQydcOFi41yHNMcKRZ39NeXlr8AxGuZJsdub8vIb12fHzcq37DTU/QtbI6WLxNg2gF9Z+8qtRwTj1UI1Q==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - } - ], - "dependencies": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "peer": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "peer": true - }, - "node_modules/pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==" - }, - "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "peer": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "engines": { - "node": ">=6" - } - }, - "node_modules/puppeteer": { - "version": "19.7.2", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-19.7.2.tgz", - "integrity": "sha512-4Lm7Qpe/LU95Svirei/jDLDvR5oMrl9BPGd7HMY5+Q28n+BhvKuW97gKkR+1LlI86bO8J3g8rG/Ll5kv9J1nlQ==", - "hasInstallScript": true, - "peer": true, - "dependencies": { - "cosmiconfig": "8.0.0", - "https-proxy-agent": "5.0.1", - "progress": "2.0.3", - "proxy-from-env": "1.1.0", - "puppeteer-core": "19.7.2" - }, - "engines": { - "node": ">=14.1.0" - } - }, - "node_modules/puppeteer-cluster": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/puppeteer-cluster/-/puppeteer-cluster-0.23.0.tgz", - "integrity": "sha512-108terIWDzPrQopmoYSPd5yDoy3FGJ2dNnoGMkGYPs6xtkdhgaECwpfZkzaRToMQPZibUOz0/dSSGgPEdXEhkQ==", - "dependencies": { - "debug": "^4.3.3" - }, - "peerDependencies": { - "puppeteer": ">=1.5.0" - } - }, - "node_modules/puppeteer-core": { - "version": "19.7.2", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-19.7.2.tgz", - "integrity": "sha512-PvI+fXqgP0uGJxkyZcX51bnzjFA73MODZOAv0fSD35yR7tvbqwtMV3/Y+hxQ0AMMwzxkEebP6c7po/muqxJvmQ==", - "peer": true, - "dependencies": { - "chromium-bidi": "0.4.4", - "cross-fetch": "3.1.5", - "debug": "4.3.4", - "devtools-protocol": "0.0.1094867", - "extract-zip": "2.0.1", - "https-proxy-agent": "5.0.1", - "proxy-from-env": "1.1.0", - "rimraf": "3.0.2", - "tar-fs": "2.1.1", - "unbzip2-stream": "1.4.3", - "ws": "8.11.0" - }, - "engines": { - "node": ">=14.1.0" - }, - "peerDependencies": { - "typescript": ">= 4.7.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/qrcode": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.1.tgz", - "integrity": "sha512-nS8NJ1Z3md8uTjKtP+SGGhfqmTCs5flU/xR623oI0JX+Wepz9R8UrRVCTBTJm3qGw3rH6jJ6MUHjkDx15cxSSg==", - "dependencies": { - "dijkstrajs": "^1.0.1", - "encode-utf8": "^1.0.3", - "pngjs": "^5.0.0", - "yargs": "^15.3.1" - }, - "bin": { - "qrcode": "bin/qrcode" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" - }, - "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/rfdc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", - "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==" - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "peer": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/seq-queue": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", - "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" - }, - "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" - }, - "node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/slick": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/slick/-/slick-1.12.2.tgz", - "integrity": "sha512-4qdtOGcBjral6YIBCWJ0ljFSKNLz9KkhbWtuGvUyRowl1kxfuE1x/Z/aJcaiilpb3do9bl5K7/1h9XC5wWpY/A==", - "engines": { - "node": "*" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" - }, - "node_modules/sqlstring": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", - "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/streamroller": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", - "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==", - "dependencies": { - "date-format": "^4.0.14", - "debug": "^4.3.4", - "fs-extra": "^8.1.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/streamroller/node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/strftime": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/strftime/-/strftime-0.10.1.tgz", - "integrity": "sha512-nVvH6JG8KlXFPC0f8lojLgEsPA18lRpLZ+RrJh/NkQV2tqOgZfbas8gcU8SFgnnqR3rWzZPYu6N2A3xzs/8rQg==", - "engines": { - "node": ">=0.2.0" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "peer": true, - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "peer": true, - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "peer": true - }, - "node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "peer": true - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==" - }, - "node_modules/unbzip2-stream": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", - "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", - "peer": true, - "dependencies": { - "buffer": "^5.2.1", - "through": "^2.3.8" - } - }, - "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/valid-data-url": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/valid-data-url/-/valid-data-url-2.0.0.tgz", - "integrity": "sha512-dyCZnv3aCey7yfTgIqdZanKl7xWAEEKCbgmR7SKqyK6QT/Z07ROactrgD1eA37C69ODRj7rNOjzKWVPh0EUjBA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "node_modules/vue": { - "version": "2.7.10", - "resolved": "https://registry.npmjs.org/vue/-/vue-2.7.10.tgz", - "integrity": "sha512-HmFC70qarSHPXcKtW8U8fgIkF6JGvjEmDiVInTkKZP0gIlEPhlVlcJJLkdGIDiNkIeA2zJPQTWJUI4iWe+AVfg==", - "dependencies": { - "@vue/compiler-sfc": "2.7.10", - "csstype": "^3.1.0" - } - }, - "node_modules/vue-i18n": { - "version": "8.27.2", - "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.27.2.tgz", - "integrity": "sha512-QVzn7u2WVH8F7eSKIM00lujC7x1mnuGPaTnDTmB01Hd709jDtB9kYtBqM+MWmp5AJRx3gnqAdZbee9MelqwFBg==" - }, - "node_modules/vue-server-renderer": { - "version": "2.7.10", - "resolved": "https://registry.npmjs.org/vue-server-renderer/-/vue-server-renderer-2.7.10.tgz", - "integrity": "sha512-hvlnyTZmDmnI7IpQE5YwIwexPi6yJq8eeNTUgLycPX3uhuEobygAQklHoeVREvwNKcET/MnVOtjF4c7t7mw6CQ==", - "dependencies": { - "chalk": "^4.1.2", - "hash-sum": "^2.0.0", - "he": "^1.2.0", - "lodash.template": "^4.5.0", - "lodash.uniq": "^4.5.0", - "resolve": "^1.22.0", - "serialize-javascript": "^6.0.0", - "source-map": "0.5.6" - } - }, - "node_modules/vue-server-renderer/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/vue-server-renderer/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/vue-server-renderer/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/vue-server-renderer/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/vue-server-renderer/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/vue-server-renderer/node_modules/source-map": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", - "integrity": "sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/vue-server-renderer/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/web-resource-inliner": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/web-resource-inliner/-/web-resource-inliner-4.3.4.tgz", - "integrity": "sha512-agVAgRhOOi4GVlvKK34oM23tDgH8390HfLnZY2HZl8OFBwKNvUJkH7t89AT2iluQP8w9VHAAKX6Z8EN7/9tqKA==", - "dependencies": { - "async": "^3.1.0", - "chalk": "^2.4.2", - "datauri": "^2.0.0", - "htmlparser2": "^4.0.0", - "lodash.unescape": "^4.0.1", - "request": "^2.88.0", - "safer-buffer": "^2.1.2", - "valid-data-url": "^2.0.0", - "xtend": "^4.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/web-resource-inliner/node_modules/dom-serializer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/web-resource-inliner/node_modules/dom-serializer/node_modules/domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/web-resource-inliner/node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/web-resource-inliner/node_modules/domhandler": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz", - "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==", - "dependencies": { - "domelementtype": "^2.0.1" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/web-resource-inliner/node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/web-resource-inliner/node_modules/domutils/node_modules/domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/web-resource-inliner/node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/web-resource-inliner/node_modules/htmlparser2": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz", - "integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==", - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^3.0.0", - "domutils": "^2.0.0", - "entities": "^2.0.0" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "peer": true - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "peer": true, - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==" - }, - "node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "peer": true - }, - "node_modules/ws": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", - "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", - "peer": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xmldom": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.6.0.tgz", - "integrity": "sha512-iAcin401y58LckRZ0TkI4k0VSM1Qg0KGSc3i8rU+xrxe19A/BN1zHyVSJY7uoutVlaTSzYyk/v5AmkewAP7jtg==", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "engines": { - "node": ">=0.4" - } - }, - "node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - }, - "node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "peer": true, - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - } - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "peer": true, - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "peer": true - }, - "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "peer": true, - "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.3.tgz", - "integrity": "sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ==" - }, - "@types/node": { - "version": "18.14.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.2.tgz", - "integrity": "sha512-1uEQxww3DaghA0RxqHx0O0ppVlo43pJhepY51OxuQIKHpjbnYLA7vcdwioNPzIqmC2u3I/dmylcqjlh0e7AyUA==", - "optional": true, - "peer": true - }, - "@types/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", - "optional": true, - "peer": true, - "requires": { - "@types/node": "*" - } - }, - "@vue/compiler-sfc": { - "version": "2.7.10", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-2.7.10.tgz", - "integrity": "sha512-55Shns6WPxlYsz4WX7q9ZJBL77sKE1ZAYNYStLs6GbhIOMrNtjMvzcob6gu3cGlfpCR4bT7NXgyJ3tly2+Hx8Q==", - "requires": { - "@babel/parser": "^7.18.4", - "postcss": "^8.4.14", - "source-map": "^0.6.1" - } - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "peer": true, - "requires": { - "debug": "4" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.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" - } - }, - "asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==" - }, - "async": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", - "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==" - }, - "aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "peer": true - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "peer": true - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "peer": true, - "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "peer": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "peer": true, - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "peer": true - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "peer": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "cheerio": { - "version": "0.22.0", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz", - "integrity": "sha512-8/MzidM6G/TgRelkzDG13y3Y9LxBjCb+8yOEZ9+wwq5gVF2w2pV0wmHvjfT0RvuxGyR7UEuK36r+yYMbT4uKgA==", - "requires": { - "css-select": "~1.2.0", - "dom-serializer": "~0.1.0", - "entities": "~1.1.1", - "htmlparser2": "^3.9.1", - "lodash.assignin": "^4.0.9", - "lodash.bind": "^4.1.4", - "lodash.defaults": "^4.0.1", - "lodash.filter": "^4.4.0", - "lodash.flatten": "^4.2.0", - "lodash.foreach": "^4.3.0", - "lodash.map": "^4.4.0", - "lodash.merge": "^4.4.0", - "lodash.pick": "^4.2.1", - "lodash.reduce": "^4.4.0", - "lodash.reject": "^4.4.0", - "lodash.some": "^4.4.0" - } - }, - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "peer": true - }, - "chromium-bidi": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.4.tgz", - "integrity": "sha512-4BX5cSaponuvVT1+SbLYTOAgDoVtX/Khoc9UsbFJ/AsPVUeFAM3RiIDFI6XFhLYMi9WmVJqh1ZH+dRpNKkKwiQ==", - "peer": true, - "requires": { - "mitt": "3.0.0" - } - }, - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "peer": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" - }, - "cosmiconfig": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.0.0.tgz", - "integrity": "sha512-da1EafcpH6b/TD8vDRaWV7xFINlHlF6zKsGwS1TsuVJTZRkquaS5HTMq7uq6h31619QjbsYl21gVDOm32KM1vQ==", - "peer": true, - "requires": { - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0" - }, - "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==", - "peer": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "peer": true, - "requires": { - "argparse": "^2.0.1" - } - } - } - }, - "cross-fetch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", - "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", - "peer": true, - "requires": { - "node-fetch": "2.6.7" - } - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "css-select": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", - "integrity": "sha512-dUQOBoqdR7QwV90WysXPLXG5LO7nhYBgiWVfxF80DKPF8zx1t/pUd2FYy73emg3zrjtM6dzmYgbHKfV2rxiHQA==", - "requires": { - "boolbase": "~1.0.0", - "css-what": "2.1", - "domutils": "1.5.1", - "nth-check": "~1.0.1" - } - }, - "css-what": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", - "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==" - }, - "csstype": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", - "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "datauri": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/datauri/-/datauri-2.0.0.tgz", - "integrity": "sha512-zS2HSf9pI5XPlNZgIqJg/wCJpecgU/HA6E/uv2EfaWnW1EiTGLfy/EexTIsC9c99yoCOTXlqeeWk4FkCSuO3/g==", - "requires": { - "image-size": "^0.7.3", - "mimer": "^1.0.0" - } - }, - "date-format": { - "version": "4.0.14", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", - "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==" - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "requires": { - "ms": "2.1.2" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==" - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" - }, - "denque": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", - "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==" - }, - "devtools-protocol": { - "version": "0.0.1094867", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1094867.tgz", - "integrity": "sha512-pmMDBKiRVjh0uKK6CT1WqZmM3hBVSgD+N2MrgyV1uNizAZMw4tx6i/RTc+/uCsKSCmg0xXx7arCP/OFcIwTsiQ==", - "peer": true - }, - "dijkstrajs": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.2.tgz", - "integrity": "sha512-QV6PMaHTCNmKSeP6QoXhVTw9snc9VD8MulTT0Bd99Pacp4SS1cjcrYPgBPmibqKVtMJJfqC6XvOXgPMEEPH/fg==" - }, - "dom-serializer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", - "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", - "requires": { - "domelementtype": "^1.3.0", - "entities": "^1.1.1" - } - }, - "domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" - }, - "domhandler": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", - "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", - "requires": { - "domelementtype": "1" - } - }, - "domutils": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", - "integrity": "sha512-gSu5Oi/I+3wDENBsOWBiRK1eoGxcywYSqg3rR960/+EfY0CF4EX1VPkgHOZ3WiS/Jg2DtliF6BhWcHlfpYUcGw==", - "requires": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "encode-utf8": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/encode-utf8/-/encode-utf8-1.0.3.tgz", - "integrity": "sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==" - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "peer": true, - "requires": { - "once": "^1.4.0" - } - }, - "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "peer": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "peer": true, - "requires": { - "@types/yauzl": "^2.9.1", - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==" - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "peer": true, - "requires": { - "pend": "~1.2.0" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==" - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==" - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "peer": true - }, - "fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "peer": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "generate-function": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", - "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", - "requires": { - "is-property": "^1.0.2" - } - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" - }, - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "peer": true, - "requires": { - "pump": "^3.0.0" - } - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "peer": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==" - }, - "har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" - }, - "hash-sum": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz", - "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==" - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" - }, - "htmlparser2": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", - "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", - "requires": { - "domelementtype": "^1.3.1", - "domhandler": "^2.3.0", - "domutils": "^1.5.1", - "entities": "^1.1.1", - "inherits": "^2.0.1", - "readable-stream": "^3.1.1" - } - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "peer": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "iconv-lite": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.2.tgz", - "integrity": "sha512-kERHXvpSaB4aU3eANwidg79K8FlrN77m8G9V+0vOR3HYaRifrlwMEpT7ZBJqLSEIHnEgJTHcWK82wwLwwKwtag==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "peer": true - }, - "image-size": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.7.5.tgz", - "integrity": "sha512-Hiyv+mXHfFEP7LzUL/llg9RwFxxY+o9N3JVLIeG5E7iFIFAalxvRU9UZthBdYDEVnzHMgjnKJPPpay5BWf1g9g==" - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "peer": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "peer": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "intl": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/intl/-/intl-1.2.5.tgz", - "integrity": "sha512-rK0KcPHeBFBcqsErKSpvZnrOmWOj+EmDkyJ57e90YWaQNqbcivcqmKDlHEeNprDWOsKzPsh1BfSpPQdDvclHVw==" - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "peer": true - }, - "is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", - "requires": { - "has": "^1.0.3" - } - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" - }, - "is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==" - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "peer": true - }, - "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" - } - }, - "jsbarcode": { - "version": "3.11.5", - "resolved": "https://registry.npmjs.org/jsbarcode/-/jsbarcode-3.11.5.tgz", - "integrity": "sha512-zv3KsH51zD00I/LrFzFSM6dst7rDn0vIMzaiZFL7qusTjPZiPtxg3zxetp0RR7obmjTw4f6NyGgbdkBCgZUIrA==" - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "peer": true - }, - "json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" - }, - "jsonexport": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonexport/-/jsonexport-3.2.0.tgz", - "integrity": "sha512-GbO9ugb0YTZatPd/hqCGR0FSwbr82H6OzG04yzdrG7XOe4QZ0jhQ+kOsB29zqkzoYJLmLxbbrFiuwbQu891XnQ==" - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - } - }, - "juice": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/juice/-/juice-5.2.0.tgz", - "integrity": "sha512-0l6GZmT3efexyaaay3SchKT5kG311N59TEFP5lfvEy0nz9SNqjx311plJ3b4jze7arsmDsiHQLh/xnAuk0HFTQ==", - "requires": { - "cheerio": "^0.22.0", - "commander": "^2.15.1", - "cross-spawn": "^6.0.5", - "deep-extend": "^0.6.0", - "mensch": "^0.3.3", - "slick": "^1.12.2", - "web-resource-inliner": "^4.3.1" - } - }, - "lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "peer": true - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "requires": { - "p-locate": "^4.1.0" - } - }, - "lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==" - }, - "lodash.assignin": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz", - "integrity": "sha512-yX/rx6d/UTVh7sSVWVSIMjfnz95evAgDFdb1ZozC35I9mSFCkmzptOzevxjgbQUsc78NR44LVHWjsoMQXy9FDg==" - }, - "lodash.bind": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz", - "integrity": "sha512-lxdsn7xxlCymgLYo1gGvVrfHmkjDiyqVv62FAeF2i5ta72BipE1SLxw8hPEPLhD4/247Ijw07UQH7Hq/chT5LA==" - }, - "lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==" - }, - "lodash.filter": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz", - "integrity": "sha512-pXYUy7PR8BCLwX5mgJ/aNtyOvuJTdZAo9EQFUvMIYugqmJxnrYaANvTbgndOzHSCSR0wnlBBfRXJL5SbWxo3FQ==" - }, - "lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==" - }, - "lodash.foreach": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", - "integrity": "sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ==" - }, - "lodash.map": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", - "integrity": "sha512-worNHGKLDetmcEYDvh2stPCrrQRkP20E4l0iIS7F8EvzMqBBi7ltvFN5m1HvTf1P7Jk1txKhvFcmYsCr8O2F1Q==" - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" - }, - "lodash.pick": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", - "integrity": "sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q==" - }, - "lodash.reduce": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz", - "integrity": "sha512-6raRe2vxCYBhpBu+B+TtNGUzah+hQjVdu3E17wfusjyrXBka2nBS8OH/gjVZ5PvHOhWmIZTYri09Z6n/QfnNMw==" - }, - "lodash.reject": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.reject/-/lodash.reject-4.6.0.tgz", - "integrity": "sha512-qkTuvgEzYdyhiJBx42YPzPo71R1aEr0z79kAv7Ixg8wPFEjgRgJdUsGMG3Hf3OYSF/kHI79XhNlt+5Ar6OzwxQ==" - }, - "lodash.some": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz", - "integrity": "sha512-j7MJE+TuT51q9ggt4fSgVqro163BEFjAt3u97IqU+JA2DkWl80nFTrowzLpZ/BnpN7rrl0JA/593NAdd8p/scQ==" - }, - "lodash.template": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", - "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", - "requires": { - "lodash._reinterpolate": "^3.0.0", - "lodash.templatesettings": "^4.0.0" - } - }, - "lodash.templatesettings": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", - "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", - "requires": { - "lodash._reinterpolate": "^3.0.0" - } - }, - "lodash.unescape": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz", - "integrity": "sha512-DhhGRshNS1aX6s5YdBE3njCCouPgnG29ebyHvImlZzXZf2SHgt+J08DHgytTPnpywNbO1Y8mNUFyQuIDBq2JZg==" - }, - "lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" - }, - "log4js": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.8.0.tgz", - "integrity": "sha512-g+V8gZyurIexrOvWQ+AcZsIvuK/lBnx2argejZxL4gVZ4Hq02kUYH6WZOnqxgBml+zzQZYdaEoTN84B6Hzm8Fg==", - "requires": { - "date-format": "^4.0.14", - "debug": "^4.3.4", - "flatted": "^3.2.7", - "rfdc": "^1.3.0", - "streamroller": "^3.1.5" - } - }, - "long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" - }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "requires": { - "yallist": "^3.0.2" - } - }, - "mensch": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/mensch/-/mensch-0.3.4.tgz", - "integrity": "sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g==" - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "requires": { - "mime-db": "1.52.0" - } - }, - "mimer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/mimer/-/mimer-1.1.1.tgz", - "integrity": "sha512-ye7CWOnSgiX3mqOLJ0bNGxRAULS5a/gzjj6lGSCnRTkbLUhNvt/7dI80b6GZRoaj4CsylcWQzyyKKh1a3CT74g==" - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "peer": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "mitt": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.0.tgz", - "integrity": "sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==", - "peer": true - }, - "mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "peer": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "mysql2": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-1.7.0.tgz", - "integrity": "sha512-xTWWQPjP5rcrceZQ7CSTKR/4XIDeH/cRkNH/uzvVGQ7W5c7EJ0dXeJUusk7OKhIoHj7uFKUxDVSCfLIl+jluog==", - "requires": { - "denque": "^1.4.1", - "generate-function": "^2.3.1", - "iconv-lite": "^0.5.0", - "long": "^4.0.0", - "lru-cache": "^5.1.1", - "named-placeholders": "^1.1.2", - "seq-queue": "^0.0.5", - "sqlstring": "^2.3.1" - } - }, - "named-placeholders": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.2.tgz", - "integrity": "sha512-wiFWqxoLL3PGVReSZpjLVxyJ1bRqe+KKJVbr4hGs1KWfTZTQyezHFBbuKj9hsizHyGV2ne7EMjHdxEGAybD5SA==", - "requires": { - "lru-cache": "^4.1.3" - }, - "dependencies": { - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==" - } - } - }, - "nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" - }, - "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "peer": true, - "requires": { - "whatwg-url": "^5.0.0" - } - }, - "nodemailer": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-4.7.0.tgz", - "integrity": "sha512-IludxDypFpYw4xpzKdMAozBSkzKHmNBvGanUREjJItgJ2NYcK/s8+PggVhj7c2yGFQykKsnnmv1+Aqo0ZfjHmw==" - }, - "nth-check": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", - "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", - "requires": { - "boolbase": "~1.0.0" - } - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "peer": true, - "requires": { - "wrappy": "1" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "peer": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "peer": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "peer": true - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==" - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "peer": true - }, - "pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "peer": true - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "pngjs": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", - "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==" - }, - "postcss": { - "version": "8.4.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.17.tgz", - "integrity": "sha512-UNxNOLQydcOFi41yHNMcKRZ39NeXlr8AxGuZJsdub8vIb12fHzcq37DTU/QtbI6WLxNg2gF9Z+8qtRwTj1UI1Q==", - "requires": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - } - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "peer": true - }, - "proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "peer": true - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==" - }, - "psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "peer": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - }, - "puppeteer": { - "version": "19.7.2", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-19.7.2.tgz", - "integrity": "sha512-4Lm7Qpe/LU95Svirei/jDLDvR5oMrl9BPGd7HMY5+Q28n+BhvKuW97gKkR+1LlI86bO8J3g8rG/Ll5kv9J1nlQ==", - "peer": true, - "requires": { - "cosmiconfig": "8.0.0", - "https-proxy-agent": "5.0.1", - "progress": "2.0.3", - "proxy-from-env": "1.1.0", - "puppeteer-core": "19.7.2" - } - }, - "puppeteer-cluster": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/puppeteer-cluster/-/puppeteer-cluster-0.23.0.tgz", - "integrity": "sha512-108terIWDzPrQopmoYSPd5yDoy3FGJ2dNnoGMkGYPs6xtkdhgaECwpfZkzaRToMQPZibUOz0/dSSGgPEdXEhkQ==", - "requires": { - "debug": "^4.3.3" - } - }, - "puppeteer-core": { - "version": "19.7.2", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-19.7.2.tgz", - "integrity": "sha512-PvI+fXqgP0uGJxkyZcX51bnzjFA73MODZOAv0fSD35yR7tvbqwtMV3/Y+hxQ0AMMwzxkEebP6c7po/muqxJvmQ==", - "peer": true, - "requires": { - "chromium-bidi": "0.4.4", - "cross-fetch": "3.1.5", - "debug": "4.3.4", - "devtools-protocol": "0.0.1094867", - "extract-zip": "2.0.1", - "https-proxy-agent": "5.0.1", - "proxy-from-env": "1.1.0", - "rimraf": "3.0.2", - "tar-fs": "2.1.1", - "unbzip2-stream": "1.4.3", - "ws": "8.11.0" - } - }, - "qrcode": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.1.tgz", - "integrity": "sha512-nS8NJ1Z3md8uTjKtP+SGGhfqmTCs5flU/xR623oI0JX+Wepz9R8UrRVCTBTJm3qGw3rH6jJ6MUHjkDx15cxSSg==", - "requires": { - "dijkstrajs": "^1.0.1", - "encode-utf8": "^1.0.3", - "pngjs": "^5.0.0", - "yargs": "^15.3.1" - } - }, - "qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==" - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" - }, - "resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "peer": true - }, - "rfdc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", - "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==" - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "peer": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - }, - "seq-queue": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", - "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" - }, - "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "requires": { - "randombytes": "^2.1.0" - } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==" - }, - "slick": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/slick/-/slick-1.12.2.tgz", - "integrity": "sha512-4qdtOGcBjral6YIBCWJ0ljFSKNLz9KkhbWtuGvUyRowl1kxfuE1x/Z/aJcaiilpb3do9bl5K7/1h9XC5wWpY/A==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" - }, - "sqlstring": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", - "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==" - }, - "sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "streamroller": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", - "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==", - "requires": { - "date-format": "^4.0.14", - "debug": "^4.3.4", - "fs-extra": "^8.1.0" - }, - "dependencies": { - "fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - } - } - }, - "strftime": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/strftime/-/strftime-0.10.1.tgz", - "integrity": "sha512-nVvH6JG8KlXFPC0f8lojLgEsPA18lRpLZ+RrJh/NkQV2tqOgZfbas8gcU8SFgnnqR3rWzZPYu6N2A3xzs/8rQg==" - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - } - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" - }, - "tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "peer": true, - "requires": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "peer": true, - "requires": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - } - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "peer": true - }, - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "peer": true - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==" - }, - "unbzip2-stream": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", - "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", - "peer": true, - "requires": { - "buffer": "^5.2.1", - "through": "^2.3.8" - } - }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "requires": { - "punycode": "^2.1.0" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" - }, - "valid-data-url": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/valid-data-url/-/valid-data-url-2.0.0.tgz", - "integrity": "sha512-dyCZnv3aCey7yfTgIqdZanKl7xWAEEKCbgmR7SKqyK6QT/Z07ROactrgD1eA37C69ODRj7rNOjzKWVPh0EUjBA==" - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "vue": { - "version": "2.7.10", - "resolved": "https://registry.npmjs.org/vue/-/vue-2.7.10.tgz", - "integrity": "sha512-HmFC70qarSHPXcKtW8U8fgIkF6JGvjEmDiVInTkKZP0gIlEPhlVlcJJLkdGIDiNkIeA2zJPQTWJUI4iWe+AVfg==", - "requires": { - "@vue/compiler-sfc": "2.7.10", - "csstype": "^3.1.0" - } - }, - "vue-i18n": { - "version": "8.27.2", - "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.27.2.tgz", - "integrity": "sha512-QVzn7u2WVH8F7eSKIM00lujC7x1mnuGPaTnDTmB01Hd709jDtB9kYtBqM+MWmp5AJRx3gnqAdZbee9MelqwFBg==" - }, - "vue-server-renderer": { - "version": "2.7.10", - "resolved": "https://registry.npmjs.org/vue-server-renderer/-/vue-server-renderer-2.7.10.tgz", - "integrity": "sha512-hvlnyTZmDmnI7IpQE5YwIwexPi6yJq8eeNTUgLycPX3uhuEobygAQklHoeVREvwNKcET/MnVOtjF4c7t7mw6CQ==", - "requires": { - "chalk": "^4.1.2", - "hash-sum": "^2.0.0", - "he": "^1.2.0", - "lodash.template": "^4.5.0", - "lodash.uniq": "^4.5.0", - "resolve": "^1.22.0", - "serialize-javascript": "^6.0.0", - "source-map": "0.5.6" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "source-map": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", - "integrity": "sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA==" - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "web-resource-inliner": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/web-resource-inliner/-/web-resource-inliner-4.3.4.tgz", - "integrity": "sha512-agVAgRhOOi4GVlvKK34oM23tDgH8390HfLnZY2HZl8OFBwKNvUJkH7t89AT2iluQP8w9VHAAKX6Z8EN7/9tqKA==", - "requires": { - "async": "^3.1.0", - "chalk": "^2.4.2", - "datauri": "^2.0.0", - "htmlparser2": "^4.0.0", - "lodash.unescape": "^4.0.1", - "request": "^2.88.0", - "safer-buffer": "^2.1.2", - "valid-data-url": "^2.0.0", - "xtend": "^4.0.2" - }, - "dependencies": { - "dom-serializer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "dependencies": { - "domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", - "requires": { - "domelementtype": "^2.2.0" - } - } - } - }, - "domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" - }, - "domhandler": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz", - "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==", - "requires": { - "domelementtype": "^2.0.1" - } - }, - "domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "requires": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "dependencies": { - "domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", - "requires": { - "domelementtype": "^2.2.0" - } - } - } - }, - "entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" - }, - "htmlparser2": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz", - "integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==", - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^3.0.0", - "domutils": "^2.0.0", - "entities": "^2.0.0" - } - } - } - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "peer": true - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "peer": true, - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==" - }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "peer": true - }, - "ws": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", - "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", - "peer": true, - "requires": {} - }, - "xmldom": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.6.0.tgz", - "integrity": "sha512-iAcin401y58LckRZ0TkI4k0VSM1Qg0KGSc3i8rU+xrxe19A/BN1zHyVSJY7uoutVlaTSzYyk/v5AmkewAP7jtg==" - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" - }, - "y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - }, - "yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - } - }, - "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "peer": true, - "requires": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - } - } -} diff --git a/print/templates/email/incoterms-authorization/attachments.json b/print/templates/email/incoterms-authorization/attachments.json new file mode 100644 index 000000000..9dfd945db --- /dev/null +++ b/print/templates/email/incoterms-authorization/attachments.json @@ -0,0 +1,6 @@ +[ + { + "filename": "incoterms-authorization.pdf", + "component": "incoterms-authorization" + } +] \ No newline at end of file diff --git a/print/templates/email/letter-debtor-nd/attachments.json b/print/templates/email/letter-debtor-nd/attachments.json new file mode 100644 index 000000000..1e21ea343 --- /dev/null +++ b/print/templates/email/letter-debtor-nd/attachments.json @@ -0,0 +1,6 @@ +[ + { + "filename": "letter-debtor.pdf", + "component": "letter-debtor" + } +] \ No newline at end of file diff --git a/print/templates/email/letter-debtor-st/attachments.json b/print/templates/email/letter-debtor-st/attachments.json new file mode 100644 index 000000000..1e21ea343 --- /dev/null +++ b/print/templates/email/letter-debtor-st/attachments.json @@ -0,0 +1,6 @@ +[ + { + "filename": "letter-debtor.pdf", + "component": "letter-debtor" + } +] \ No newline at end of file diff --git a/print/templates/reports/balance-compensation/balance-compensation.html b/print/templates/reports/balance-compensation/balance-compensation.html index d1a2788ed..c7448eeb9 100644 --- a/print/templates/reports/balance-compensation/balance-compensation.html +++ b/print/templates/reports/balance-compensation/balance-compensation.html @@ -17,8 +17,8 @@

{{$t('Agree') | uppercase}}

- {{$t('Date')}} {{client.payed | date('%d-%m-%Y')}} {{$t('Compensate')}} {{client.amountPaid}} € - {{$t('From client')}} {{client.name}} {{$t('Against the balance of')}}: {{client.invoiceFk}}. + {{$t('Date')}} {{formatDate(receipt.payed, '%d-%m-%Y')}} {{$t('Compensate')}} {{receipt.amountPaid}} € + {{$t('From client')}} {{client.name}} {{$t('Against the balance of')}}: {{receipt.description}}.

{{$t('Reception')}} administracion@verdnatura.es diff --git a/print/templates/reports/balance-compensation/balance-compensation.js b/print/templates/reports/balance-compensation/balance-compensation.js index bae7c5c3c..c2c2e9288 100644 --- a/print/templates/reports/balance-compensation/balance-compensation.js +++ b/print/templates/reports/balance-compensation/balance-compensation.js @@ -1,12 +1,31 @@ const vnReport = require('../../../core/mixins/vn-report.js'); +const app = require('vn-loopback/server/server'); module.exports = { name: 'balance-compensation', mixins: [vnReport], async serverPrefetch() { - this.client = await this.findOneFromDef('client', [this.id]); - this.checkMainEntity(this.client); - this.company = await this.findOneFromDef('company', [this.id]); + this.receipt = await app.models.Receipt.findOne({ + fields: ['amountPaid', 'payed', 'clientFk', 'companyFk', 'description'], + include: [ + { + relation: 'client', + scope: { + fields: ['name', 'street', 'fi', 'city'], + } + }, { + relation: 'supplier', + scope: { + fields: ['name', 'street', 'nif', 'city'], + } + } + ], + where: {id: this.id} + }); + this.client = this.receipt.client(); + this.company = this.receipt.supplier(); + + this.checkMainEntity(this.receipt); }, props: { id: { diff --git a/print/templates/reports/balance-compensation/sql/client.sql b/print/templates/reports/balance-compensation/sql/client.sql deleted file mode 100644 index c3679b68a..000000000 --- a/print/templates/reports/balance-compensation/sql/client.sql +++ /dev/null @@ -1,12 +0,0 @@ -SELECT - c.name, - c.socialName, - c.street, - c.fi, - c.city, - r.invoiceFk, - r.amountPaid, - r.payed - FROM client c - JOIN receipt r ON r.clientFk = c.id - WHERE r.id = ? diff --git a/print/templates/reports/balance-compensation/sql/company.sql b/print/templates/reports/balance-compensation/sql/company.sql deleted file mode 100644 index e61228a10..000000000 --- a/print/templates/reports/balance-compensation/sql/company.sql +++ /dev/null @@ -1,8 +0,0 @@ -SELECT - s.name, - s.nif, - s.street, - s.city - FROM supplier s - JOIN receipt r ON r.companyFk = s.id - WHERE r.id = ?; \ No newline at end of file diff --git a/print/templates/reports/delivery-note/delivery-note.html b/print/templates/reports/delivery-note/delivery-note.html index eb133c0cd..0be5a30f0 100644 --- a/print/templates/reports/delivery-note/delivery-note.html +++ b/print/templates/reports/delivery-note/delivery-note.html @@ -33,7 +33,7 @@

{{$t('deliveryAddress')}}
-
+

{{address.nickname}}

{{address.street}}
{{address.postalCode}}, {{address.city}} ({{address.province}})
@@ -245,13 +245,8 @@
- + \ No newline at end of file diff --git a/print/templates/reports/expedition-pallet-label/sql/labelData.sql b/print/templates/reports/expedition-pallet-label/sql/labelData.sql index 0661dbe0f..b2a805251 100644 --- a/print/templates/reports/expedition-pallet-label/sql/labelData.sql +++ b/print/templates/reports/expedition-pallet-label/sql/labelData.sql @@ -12,8 +12,8 @@ SELECT ep.id palletFk, JOIN vn.expedition e ON e.id = es.expeditionFk JOIN vn.ticket t ON t.id = e.ticketFk JOIN vn.route r ON r.id = t.routeFk - LEFT JOIN vn2008.Rutas_monitor rm ON rm.Id_Ruta = r.id + LEFT JOIN vn.routesMonitor rm ON rm.routeFk = r.id LEFT JOIN vn.expeditionTruck et2 ON et2.id = rm.expeditionTruckFk WHERE ep.id = ? GROUP BY ep.id, t.routeFk - ORDER BY t.routeFk \ No newline at end of file + ORDER BY t.routeFk diff --git a/print/templates/reports/extra-community/extra-community.html b/print/templates/reports/extra-community/extra-community.html index cd61a4f4d..3153b6b03 100644 --- a/print/templates/reports/extra-community/extra-community.html +++ b/print/templates/reports/extra-community/extra-community.html @@ -51,7 +51,7 @@
- + diff --git a/print/templates/reports/extra-community/extra-community.js b/print/templates/reports/extra-community/extra-community.js index 9941faa35..5d875d78f 100755 --- a/print/templates/reports/extra-community/extra-community.js +++ b/print/templates/reports/extra-community/extra-community.js @@ -1,11 +1,12 @@ const vnReport = require('../../../core/mixins/vn-report.js'); -const db = require(`vn-print/core/database`); +const app = require('vn-loopback/server/server'); module.exports = { name: 'extra-community', mixins: [vnReport], async serverPrefetch() { const args = { + search: this.search, landedTo: this.landedEnd, shippedFrom: this.shippedStart, continent: this.continent, @@ -17,76 +18,24 @@ module.exports = { ref: this.ref, cargoSupplierFk: this.cargoSupplierFk }; - - const travels = await this.fetchTravels(args); - this.checkMainEntity(travels); - const travelIds = travels.map(travel => travel.id); - const entries = await this.rawSqlFromDef('entries', [travelIds]); - - const map = new Map(); - for (let travel of travels) - map.set(travel.id, travel); - - for (let entry of entries) { - const travel = map.get(entry.travelFk); - if (!travel.entries) travel.entries = []; - travel.entries.push(entry); - } - - this.travels = travels; + const ctx = {args: args}; + this.travels = await app.models.Travel.extraCommunityFilter(ctx, this.filter); }, computed: { landedEnd: function() { if (!this.landedTo) return; - return formatDate(this.landedTo, '%Y-%m-%d'); + return this.formatDate(this.landedTo, '%Y-%m-%d'); }, shippedStart: function() { if (!this.shippedFrom) return; - return formatDate(this.shippedFrom, '%Y-%m-%d'); + return this.formatDate(this.shippedFrom, '%Y-%m-%d'); } }, methods: { - fetchTravels(args) { - const where = db.buildWhere(args, (key, value) => { - switch (key) { - case 'shippedFrom': - return `t.shipped >= ${value}`; - case 'landedTo': - return `t.landed <= ${value}`; - case 'continent': - return `cnt.code = ${value}`; - case 'ref': - return {'t.ref': {like: `%${value}%`}}; - case 'id': - return `t.id = ${value}`; - case 'agencyModeFk': - return `am.id = ${value}`; - case 'warehouseOutFk': - return `wo.id = ${value}`; - case 'warehouseInFk': - return `w.id = ${value}`; - case 'cargoSupplierFk': - return `s.id = ${value}`; - } - }); - - let query = this.getSqlFromDef('travels'); - query = db.merge(query, where); - query = db.merge(query, 'GROUP BY t.id'); - query = db.merge(query, ` - ORDER BY - shipped ASC, - landed ASC, - travelFk, - loadPriority, - agencyModeFk, - evaNotes - `); - - return this.rawSql(query); - }, }, props: [ + 'filter', + 'search', 'landedTo', 'shippedFrom', 'continent', diff --git a/print/templates/reports/extra-community/sql/entries.sql b/print/templates/reports/extra-community/sql/entries.sql deleted file mode 100644 index 84dc497c0..000000000 --- a/print/templates/reports/extra-community/sql/entries.sql +++ /dev/null @@ -1,18 +0,0 @@ -SELECT - e.id, - e.travelFk, - e.reference, - s.name AS supplierName, - SUM(b.stickers) AS stickers, - CAST(SUM(b.weight * b.stickers) as DECIMAL(10,0)) as loadedKg, - CAST(SUM(vc.aerealVolumetricDensity * b.stickers * IF(pkg.volume, pkg.volume, pkg.width * pkg.depth * pkg.height) / 1000000) as DECIMAL(10,0)) as volumeKg - FROM travel t - JOIN entry e ON e.travelFk = t.id - JOIN buy b ON b.entryFk = e.id - JOIN packaging pkg ON pkg.id = b.packageFk - JOIN item i ON i.id = b.itemFk - JOIN itemType it ON it.id = i.typeFk - JOIN supplier s ON s.id = e.supplierFk - JOIN vn.volumeConfig vc - WHERE t.id IN(?) - GROUP BY e.id diff --git a/print/templates/reports/extra-community/sql/travels.sql b/print/templates/reports/extra-community/sql/travels.sql deleted file mode 100644 index b0987c330..000000000 --- a/print/templates/reports/extra-community/sql/travels.sql +++ /dev/null @@ -1,23 +0,0 @@ -SELECT - t.id, - t.ref, - t.shipped, - t.landed, - t.kg, - am.id AS agencyModeFk, - SUM(b.stickers) AS stickers, - CAST(SUM(b.weight * b.stickers) as DECIMAL(10,0)) as loadedKg, - CAST(SUM(vc.aerealVolumetricDensity * b.stickers * IF(pkg.volume, pkg.volume, pkg.width * pkg.depth * pkg.height) / 1000000) as DECIMAL(10,0)) as volumeKg -FROM travel t - JOIN volumeConfig vc - LEFT JOIN supplier s ON s.id = t.cargoSupplierFk - LEFT JOIN entry e ON e.travelFk = t.id - LEFT JOIN buy b ON b.entryFk = e.id - LEFT JOIN packaging pkg ON pkg.id = b.packageFk - LEFT JOIN item i ON i.id = b.itemFk - LEFT JOIN itemType it ON it.id = i.typeFk - JOIN warehouse w ON w.id = t.warehouseInFk - JOIN warehouse wo ON wo.id = t.warehouseOutFk - JOIN country c ON c.id = wo.countryFk - LEFT JOIN continent cnt ON cnt.id = c.continentFk - JOIN agencyMode am ON am.id = t.agencyModeFk \ No newline at end of file diff --git a/print/templates/reports/invoice/invoice.html b/print/templates/reports/invoice/invoice.html index 771229c01..9fb1b0a37 100644 --- a/print/templates/reports/invoice/invoice.html +++ b/print/templates/reports/invoice/invoice.html @@ -240,13 +240,22 @@
+ + + Item ID Description - Warehouse - Grouping price @@ -57,13 +66,24 @@ Ended + Warehouse +
+ + + - {{price.name}} + {{itemFk.selection.name}}

{{price.subName}}

@@ -100,18 +120,11 @@ tabindex="-1">
- - - - {{price.rate2 | currency: 'EUR':2}} + + {{price.rate2 | currency: 'EUR':2}} + - {{price.rate3 | currency: 'EUR':2}} + + {{price.rate3 | currency: 'EUR':2}} + + ng-model="price.hasMinPrice" + on-change="$ctrl.upsertPrice(price)"> - - + + + + - + + + + + - + ng-model="price.warehouseFk" + data="warehouses" + on-change="$ctrl.upsertPrice(price)" + tabindex="2"> + + +
+ + + + +
+ + + Edit + + {{::$ctrl.totalChecked}} + + buy(s) + + + + + + + + + + + + + + + + + + + diff --git a/modules/item/front/fixed-price/index.js b/modules/item/front/fixed-price/index.js index df2989043..a39cd6602 100644 --- a/modules/item/front/fixed-price/index.js +++ b/modules/item/front/fixed-price/index.js @@ -5,6 +5,9 @@ import './style.scss'; export default class Controller extends Section { constructor($element, $) { super($element, $); + this.editedColumn; + this.checkAll = false; + this.checkedFixedPrices = []; this.smartTableOptions = { activeButtons: { @@ -30,13 +33,146 @@ export default class Controller extends Section { } ] }; + + this.filterParams = { + warehouseFk: this.vnConfig.warehouseFk + }; + } + + getFilterParams() { + return { + warehouseFk: this.vnConfig.warehouseFk + }; + } + + get columns() { + if (this._columns) return this._columns; + + this._columns = [ + {field: 'rate2', displayName: this.$t('Grouping price')}, + {field: 'rate3', displayName: this.$t('Packing price')}, + {field: 'hasMinPrice', displayName: this.$t('Has min price')}, + {field: 'minPrice', displayName: this.$t('Min price')}, + {field: 'started', displayName: this.$t('Started')}, + {field: 'ended', displayName: this.$t('Ended')}, + {field: 'warehouseFk', displayName: this.$t('Warehouse')} + ]; + + return this._columns; + } + + get checked() { + const fixedPrices = this.$.model.data || []; + const checkedBuys = []; + for (let fixedPrice of fixedPrices) { + if (fixedPrice.checked) + checkedBuys.push(fixedPrice); + } + + return checkedBuys; + } + + uncheck() { + this.checkAll = false; + this.checkedFixedPrices = []; + } + + get totalChecked() { + if (this.checkedDummyCount) + return this.checkedDummyCount; + + return this.checked.length; + } + + saveChecked(fixedPriceId) { + const index = this.checkedFixedPrices.indexOf(fixedPriceId); + if (index !== -1) + return this.checkedFixedPrices.splice(index, 1); + return this.checkedFixedPrices.push(fixedPriceId); + } + + reCheck() { + if (!this.$.model.data) return; + if (!this.checkedFixedPrices.length) return; + + this.$.model.data.forEach(fixedPrice => { + if (this.checkedFixedPrices.includes(fixedPrice.id)) + fixedPrice.checked = true; + }); + } + + onEditAccept() { + const rowsToEdit = []; + for (let row of this.checked) + rowsToEdit.push({id: row.id, itemFk: row.itemFk}); + + const data = { + field: this.editedColumn.field, + newValue: this.editedColumn.newValue, + lines: rowsToEdit + }; + + if (this.checkedDummyCount && this.checkedDummyCount > 0) { + const params = {}; + if (this.$.model.userParams) { + const userParams = this.$.model.userParams; + for (let param in userParams) { + let newParam = this.exprBuilder(param, userParams[param]); + if (!newParam) + newParam = {[param]: userParams[param]}; + Object.assign(params, newParam); + } + } + if (this.$.model.userFilter) + Object.assign(params, this.$.model.userFilter.where); + + data.filter = params; + } + + return this.$http.post('FixedPrices/editFixedPrice', data) + .then(() => { + this.uncheck(); + this.$.model.refresh(); + }); + } + + isBigger(date) { + let today = Date.vnNew(); + today.setHours(0, 0, 0, 0); + + date = new Date(date); + date.setHours(0, 0, 0, 0); + + const timeDifference = today - date; + if (timeDifference < 0) return 'warning'; + } + + isLower(date) { + let today = Date.vnNew(); + today.setHours(0, 0, 0, 0); + + date = new Date(date); + date.setHours(0, 0, 0, 0); + + const timeDifference = today - date; + if (timeDifference > 0) return 'warning'; } add() { if (!this.$.model.data || this.$.model.data.length == 0) { this.$.model.data = []; this.$.model.proxiedData = []; - this.$.model.insert({}); + + const today = Date.vnNew(); + + const millisecsInDay = 86400000; + const daysInWeek = 7; + const nextWeek = new Date(today.getTime() + daysInWeek * millisecsInDay); + + this.$.model.insert({ + started: today, + ended: nextWeek + }); return; } @@ -66,10 +202,8 @@ export default class Controller extends Section { if (resetMinPrice) delete price['minPrice']; - price.hasMinPrice = price.minPrice ? true : false; - - let requiredFields = ['itemFk', 'started', 'ended', 'rate2', 'rate3']; - for (let field of requiredFields) + const requiredFields = ['itemFk', 'started', 'ended', 'rate2', 'rate3']; + for (const field of requiredFields) if (price[field] == undefined) return; const query = 'FixedPrices/upsertFixedPrice'; diff --git a/modules/item/front/fixed-price/index.spec.js b/modules/item/front/fixed-price/index.spec.js index 42dd898b3..ae24da60b 100644 --- a/modules/item/front/fixed-price/index.spec.js +++ b/modules/item/front/fixed-price/index.spec.js @@ -12,8 +12,92 @@ describe('fixed price', () => { const $scope = $rootScope.$new(); const $element = angular.element(''); controller = $componentController('vnFixedPrice', {$element, $scope}); + controller.$ = { + model: {refresh: () => {}}, + edit: {hide: () => {}} + }; })); + describe('get columns', () => { + it(`should return a set of columns`, () => { + let result = controller.columns; + + let length = result.length; + let anyColumn = Object.keys(result[Math.floor(Math.random() * Math.floor(length))]); + + expect(anyColumn).toContain('field', 'displayName'); + }); + }); + + describe('get checked', () => { + it(`should return a set of checked lines`, () => { + controller.$.model.data = [ + {checked: true, id: 1}, + {checked: true, id: 2}, + {checked: true, id: 3}, + {checked: false, id: 4}, + ]; + + let result = controller.checked; + + expect(result.length).toEqual(3); + }); + }); + + describe('reCheck()', () => { + it(`should recheck buys`, () => { + controller.$.model.data = [ + {checked: false, id: 1}, + {checked: false, id: 2}, + {checked: false, id: 3}, + {checked: false, id: 4}, + ]; + controller.checkedFixedPrices = [1, 2]; + + controller.reCheck(); + + expect(controller.$.model.data[0].checked).toEqual(true); + expect(controller.$.model.data[1].checked).toEqual(true); + expect(controller.$.model.data[2].checked).toEqual(false); + expect(controller.$.model.data[3].checked).toEqual(false); + }); + }); + + describe('saveChecked()', () => { + it(`should check buy`, () => { + const buyCheck = 3; + controller.checkedFixedPrices = [1, 2]; + + controller.saveChecked(buyCheck); + + expect(controller.checkedFixedPrices[2]).toEqual(buyCheck); + }); + + it(`should uncheck buy`, () => { + const buyUncheck = 3; + controller.checkedFixedPrices = [1, 2, 3]; + + controller.saveChecked(buyUncheck); + + expect(controller.checkedFixedPrices[2]).toEqual(undefined); + }); + }); + + describe('onEditAccept()', () => { + it(`should perform a query to update columns`, () => { + controller.editedColumn = {field: 'my field', newValue: 'the new value'}; + const query = 'FixedPrices/editFixedPrice'; + + $httpBackend.expectPOST(query).respond(); + controller.onEditAccept(); + $httpBackend.flush(); + + const result = controller.checked; + + expect(result.length).toEqual(0); + }); + }); + describe('upsertPrice()', () => { it('should do nothing if one or more required arguments are missing', () => { jest.spyOn(controller.vnApp, 'showSuccess'); diff --git a/modules/item/front/fixed-price/locale/es.yml b/modules/item/front/fixed-price/locale/es.yml index 6bdfcb678..6dacf96c9 100644 --- a/modules/item/front/fixed-price/locale/es.yml +++ b/modules/item/front/fixed-price/locale/es.yml @@ -3,3 +3,5 @@ Search prices by item ID or code: Buscar por ID de artículo o código Search fixed prices: Buscar precios fijados Add fixed price: Añadir precio fijado This row will be removed: Esta linea se eliminará +Edit fixed price(s): Editar precio(s) fijado(s) +Has min price: Tiene precio mínimo diff --git a/modules/item/front/fixed-price/style.scss b/modules/item/front/fixed-price/style.scss index ba3878dba..97ceaf7cd 100644 --- a/modules/item/front/fixed-price/style.scss +++ b/modules/item/front/fixed-price/style.scss @@ -1,20 +1,46 @@ @import "variables"; -smart-table table{ - [shrink-field]{ - width: 80px; - max-width: 80px; +vn-fixed-price{ + smart-table table{ + [shrink-field]{ + width: 80px; + max-width: 80px; + } + [shrink-field-expand]{ + width: 150px; + max-width: 150px; + } } - [shrink-field-expand]{ - width: 150px; - max-width: 150px; + + .minPrice { + align-items: center; + text-align: center; + vn-input-number { + width: 90px; + max-width: 90px; + } + } + + smart-table table tbody > * > td .chip { + padding: 0px; + } + + smart-table table tbody > * > td{ + padding: 0px; + padding-left: 5px; + padding-right: 5px; + } + + smart-table table tbody > * > td .chip.warning { + color: $color-font-bg + } + + .vn-field > .container > .infix > .control > input { + color: inherit; + } + + vn-input-number.inactive{ + input { + color: $color-font-light !important; + } } } - -.minPrice { - align-items: center; - text-align: center; - vn-input-number { - width: 90px; - max-width: 90px; - } -} \ No newline at end of file diff --git a/modules/item/front/last-entries/index.html b/modules/item/front/last-entries/index.html index f6cdf8343..609cdb7fa 100644 --- a/modules/item/front/last-entries/index.html +++ b/modules/item/front/last-entries/index.html @@ -86,11 +86,11 @@ class="expendable"> - {{::entry.cost | currency: 'EUR':2 | dashIfEmpty}} + {{::$ctrl.$t('Cost')}}: {{::entry.buyingValue | currency: 'EUR':3 | dashIfEmpty}}
+ {{::$ctrl.$t('Package')}}: {{::entry.packageValue | currency: 'EUR':3 | dashIfEmpty}}
+ {{::$ctrl.$t('Freight')}}: {{::entry.freightValue | currency: 'EUR':3 | dashIfEmpty}}
+ {{::$ctrl.$t('Comission')}}: {{::entry.comissionValue | currency: 'EUR':3 | dashIfEmpty}}"> + {{::entry.cost | currency: 'EUR':3 | dashIfEmpty}}
{{::entry.weight | dashIfEmpty}} diff --git a/modules/item/front/locale/es.yml b/modules/item/front/locale/es.yml index 0fc014742..37f774e4e 100644 --- a/modules/item/front/locale/es.yml +++ b/modules/item/front/locale/es.yml @@ -40,11 +40,11 @@ Create: Crear Client card: Ficha del cliente Shipped: F. envío stems: Tallos -Weight/Piece: Peso/tallo +Weight/Piece: Peso (gramos)/tallo Search items by id, name or barcode: Buscar articulos por identificador, nombre o codigo de barras SalesPerson: Comercial Concept: Concepto -Units/Box: Unidades/Caja +Units/Box: Unidades/caja # Sections Items: Artículos diff --git a/modules/item/front/request-search-panel/index.html b/modules/item/front/request-search-panel/index.html index 8c9d04b64..a431d4fd6 100644 --- a/modules/item/front/request-search-panel/index.html +++ b/modules/item/front/request-search-panel/index.html @@ -38,6 +38,19 @@ url="Warehouses"> + + + {{firstName}} {{lastName}} + + +
{ risk = t.debt + t.credit, totalProblems = totalProblems + 1 `); + stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.sale_getWarnings'); + stmt = new ParameterizedSQL(` - SELECT t.*, tp.*, - ((tp.risk) + cc.riskTolerance < 0) AS hasHighRisk + CREATE TEMPORARY TABLE tmp.sale_getWarnings + (INDEX (ticketFk, agencyModeFk)) + ENGINE = MEMORY + SELECT f.id ticketFk, f.agencyModeFk + FROM tmp.filter f`); + stmts.push(stmt); + + stmts.push('CALL ticket_getWarnings()'); + + stmt = new ParameterizedSQL(` + SELECT t.*, + tp.*, + ((tp.risk) + cc.riskTolerance < 0) AS hasHighRisk, + tw.* FROM tmp.tickets t LEFT JOIN tmp.ticket_problems tp ON tp.ticketFk = t.id + LEFT JOIN tmp.ticket_warnings tw ON tw.ticketFk = t.id JOIN clientConfig cc`); const hasProblems = args.problems; @@ -352,20 +367,37 @@ module.exports = Self => { return {'t.alertLevel': value}; case 'pending': if (value) { - return {and: [ - {'t.alertLevel': 0}, - {'t.alertLevelCode': {nin: [ - 'OK', - 'BOARDING', - 'PRINTED', - 'PRINTED_AUTO', - 'PICKER_DESIGNED' - ]}} - ]}; + return {'t.alertLevelCode': {inq: [ + 'FIXING', + 'FREE', + 'NOT_READY', + 'BLOCKED', + 'EXPANDABLE', + 'CHAINED', + 'WAITING_FOR_PAYMENT' + ]}}; } else { - return {and: [ - {'t.alertLevel': {gt: 0}} - ]}; + return {'t.alertLevelCode': {inq: [ + 'ON_PREPARATION', + 'ON_CHECKING', + 'CHECKED', + 'PACKING', + 'PACKED', + 'INVOICED', + 'ON_DELIVERY', + 'PREPARED', + 'WAITING_FOR_PICKUP', + 'DELIVERED', + 'PRINTED_BACK', + 'LAST_CALL', + 'PREVIOUS_PREPARATION', + 'ASSISTED_PREPARATION', + 'BOARD', + 'PRINTED STOWAWAY', + 'OK STOWAWAY', + 'HALF_PACKED', + 'COOLER_PREPARATION' + ]}}; } case 'agencyModeFk': case 'warehouseFk': @@ -387,6 +419,8 @@ module.exports = Self => { tmp.filter, tmp.ticket_problems, tmp.sale_getProblems, + tmp.sale_getWarnings, + tmp.ticket_warnings, tmp.risk`); const sql = ParameterizedSQL.join(stmts, ';'); diff --git a/modules/monitor/front/index/locale/es.yml b/modules/monitor/front/index/locale/es.yml index 126528caa..f114a2259 100644 --- a/modules/monitor/front/index/locale/es.yml +++ b/modules/monitor/front/index/locale/es.yml @@ -12,4 +12,5 @@ Theoretical: Teórica Practical: Práctica Preparation: Preparación Auto-refresh: Auto-refresco -Toggle auto-refresh every 2 minutes: Conmuta el refresco automático cada 2 minutos \ No newline at end of file +Toggle auto-refresh every 2 minutes: Conmuta el refresco automático cada 2 minutos +Is fragile: Es frágil diff --git a/modules/monitor/front/index/tickets/index.html b/modules/monitor/front/index/tickets/index.html index b8559154e..539d4b3cb 100644 --- a/modules/monitor/front/index/tickets/index.html +++ b/modules/monitor/front/index/tickets/index.html @@ -19,13 +19,13 @@ Tickets monitor - + - State +
Zone
+ + + - Filter by selection - Exclude selection - Remove filter - Remove all filters - Copy value diff --git a/modules/route/back/methods/agency-term/specs/createInvoiceIn.spec.js b/modules/route/back/methods/agency-term/specs/createInvoiceIn.spec.js index 2a8ebdba3..628c5fb9a 100644 --- a/modules/route/back/methods/agency-term/specs/createInvoiceIn.spec.js +++ b/modules/route/back/methods/agency-term/specs/createInvoiceIn.spec.js @@ -1,6 +1,20 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('AgencyTerm createInvoiceIn()', () => { + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); const rows = [ { routeFk: 2, diff --git a/modules/route/back/methods/route/driverRouteEmail.js b/modules/route/back/methods/route/driverRouteEmail.js index 4d5279d2d..82b005e44 100644 --- a/modules/route/back/methods/route/driverRouteEmail.js +++ b/modules/route/back/methods/route/driverRouteEmail.js @@ -1,5 +1,3 @@ -const {Email} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('driverRouteEmail', { description: 'Sends the driver route email with an attached PDF', @@ -41,19 +39,5 @@ module.exports = Self => { } }); - Self.driverRouteEmail = async ctx => { - 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('driver-route', params); - - return email.send(); - }; + Self.driverRouteEmail = ctx => Self.sendTemplate(ctx, 'driver-route'); }; diff --git a/modules/route/back/methods/route/driverRoutePdf.js b/modules/route/back/methods/route/driverRoutePdf.js index 65748afad..f0cd75f0e 100644 --- a/modules/route/back/methods/route/driverRoutePdf.js +++ b/modules/route/back/methods/route/driverRoutePdf.js @@ -1,5 +1,3 @@ -const {Report} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('driverRoutePdf', { description: 'Returns the driver route pdf', @@ -39,17 +37,5 @@ module.exports = Self => { } }); - Self.driverRoutePdf = 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('driver-route', params); - const stream = await report.toPdfStream(); - - return [stream, 'application/pdf', `filename="doc-${id}.pdf"`]; - }; + Self.driverRoutePdf = (ctx, id) => Self.printReport(ctx, id, 'driver-route'); }; diff --git a/modules/route/back/methods/route/specs/clone.spec.js b/modules/route/back/methods/route/specs/clone.spec.js index 9192854f8..496ae1c89 100644 --- a/modules/route/back/methods/route/specs/clone.spec.js +++ b/modules/route/back/methods/route/specs/clone.spec.js @@ -1,6 +1,22 @@ const app = require('vn-loopback/server/server'); +const LoopBackContext = require('loopback-context'); describe('route clone()', () => { + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); + const createdDate = Date.vnNew(); it('should throw an error if the amount of ids pased to the clone function do no match the database', async() => { const ids = [996, 997, 998, 999]; diff --git a/modules/route/back/methods/route/specs/updateWorkCenter.spec.js b/modules/route/back/methods/route/specs/updateWorkCenter.spec.js index 5328dc240..baa63f226 100644 --- a/modules/route/back/methods/route/specs/updateWorkCenter.spec.js +++ b/modules/route/back/methods/route/specs/updateWorkCenter.spec.js @@ -1,6 +1,20 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('route updateWorkCenter()', () => { + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); const routeId = 1; it('should set the commission work center if the worker has workCenter', async() => { diff --git a/modules/route/back/models/route.json b/modules/route/back/models/route.json index 12b9785db..cdb64dd71 100644 --- a/modules/route/back/models/route.json +++ b/modules/route/back/models/route.json @@ -1,9 +1,6 @@ { "name": "Route", "base": "Loggable", - "log": { - "model":"RouteLog" - }, "options": { "mysql": { "table": "route" diff --git a/modules/shelving/back/models/shelving.json b/modules/shelving/back/models/shelving.json index 508ac428f..5f60318a5 100644 --- a/modules/shelving/back/models/shelving.json +++ b/modules/shelving/back/models/shelving.json @@ -1,10 +1,6 @@ { "name": "Shelving", "base": "Loggable", - "log": { - "model": "ShelvingLog", - "showField": "id" - }, "options": { "mysql": { "table": "shelving" diff --git a/modules/supplier/back/methods/supplier/campaignMetricsPdf.js b/modules/supplier/back/methods/supplier/campaignMetricsPdf.js index 7bd65ffcb..f7ff900e7 100644 --- a/modules/supplier/back/methods/supplier/campaignMetricsPdf.js +++ b/modules/supplier/back/methods/supplier/campaignMetricsPdf.js @@ -1,5 +1,3 @@ -const {Report} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('campaignMetricsPdf', { description: 'Returns the campaign metrics pdf', @@ -49,17 +47,5 @@ module.exports = Self => { } }); - Self.campaignMetricsPdf = 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('supplier-campaign-metrics', params); - const stream = await report.toPdfStream(); - - return [stream, 'application/pdf', `filename="doc-${id}.pdf"`]; - }; + Self.campaignMetricsPdf = (ctx, id) => Self.printReport(ctx, id, 'supplier-campaign-metrics'); }; diff --git a/modules/supplier/back/methods/supplier/newSupplier.js b/modules/supplier/back/methods/supplier/newSupplier.js index ae71380f3..c40e7214f 100644 --- a/modules/supplier/back/methods/supplier/newSupplier.js +++ b/modules/supplier/back/methods/supplier/newSupplier.js @@ -1,11 +1,10 @@ module.exports = Self => { - Self.remoteMethod('newSupplier', { + Self.remoteMethodCtx('newSupplier', { description: 'Creates a new supplier and returns it', accessType: 'WRITE', accepts: [{ - arg: 'params', - type: 'object', - http: {source: 'body'} + arg: 'name', + type: 'string' }], returns: { type: 'string', @@ -17,29 +16,18 @@ module.exports = Self => { } }); - Self.newSupplier = async params => { + Self.newSupplier = async(ctx, options) => { const models = Self.app.models; + const args = ctx.args; const myOptions = {}; - if (typeof(params) == 'string') - params = JSON.parse(params); + if (typeof options == 'object') + Object.assign(myOptions, options); - params.nickname = params.name; + delete args.ctx; + const data = {...args, ...{nickname: args.name}}; + const supplier = await models.Supplier.create(data, myOptions); - if (!myOptions.transaction) { - tx = await Self.beginTransaction({}); - myOptions.transaction = tx; - } - - try { - const supplier = await models.Supplier.create(params, myOptions); - - if (tx) await tx.commit(); - - return supplier; - } catch (e) { - if (tx) await tx.rollback(); - throw e; - } + return supplier; }; }; diff --git a/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js b/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js index 44252e71b..d4479d00b 100644 --- a/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js +++ b/modules/supplier/back/methods/supplier/specs/newSupplier.spec.js @@ -1,31 +1,39 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; const LoopBackContext = require('loopback-context'); describe('Supplier newSupplier()', () => { - const newSupp = { - name: 'TestSupplier-1' - }; const administrativeId = 5; + const activeCtx = { + accessToken: {userId: administrativeId}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + const ctx = {req: activeCtx}; - it('should create a new supplier containing only the name', async() => { - pending('https://redmine.verdnatura.es/issues/5203'); - const activeCtx = { - accessToken: {userId: administrativeId}, - }; + beforeEach(() => { spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ active: activeCtx }); + }); - let result = await app.models.Supplier.newSupplier(JSON.stringify(newSupp)); + it('should create a new supplier containing only the name', async() => { + const tx = await models.Supplier.beginTransaction({}); - expect(result.name).toEqual('TestSupplier-1'); - expect(result.id).toEqual(443); + try { + const options = {transaction: tx}; + ctx.args = { + name: 'newSupplier' + }; - const createdSupplier = await app.models.Supplier.findById(result.id); + const result = await models.Supplier.newSupplier(ctx, options); - expect(createdSupplier.id).toEqual(result.id); - expect(createdSupplier.name).toEqual(result.name); - expect(createdSupplier.payDemFk).toEqual(7); - expect(createdSupplier.nickname).toEqual(result.name); + expect(result.name).toEqual('newSupplier'); + } catch (e) { + await tx.rollback(); + throw e; + } }); }); diff --git a/modules/supplier/back/models/supplier-account.json b/modules/supplier/back/models/supplier-account.json index 2ee83338b..bc9cf0e24 100644 --- a/modules/supplier/back/models/supplier-account.json +++ b/modules/supplier/back/models/supplier-account.json @@ -1,10 +1,6 @@ { "name": "SupplierAccount", "base": "Loggable", - "log": { - "model":"SupplierLog", - "relation": "supplier" - }, "options": { "mysql": { "table": "supplierAccount" @@ -35,4 +31,4 @@ "foreignKey": "bankEntityFk" } } -} \ No newline at end of file +} diff --git a/modules/supplier/back/models/supplier-address.json b/modules/supplier/back/models/supplier-address.json index 302f15e4b..001b3a31f 100644 --- a/modules/supplier/back/models/supplier-address.json +++ b/modules/supplier/back/models/supplier-address.json @@ -2,11 +2,6 @@ "name": "SupplierAddress", "description": "Supplier addresses", "base": "Loggable", - "log": { - "model": "SupplierLog", - "relation": "supplier", - "showField": "name" - }, "options": { "mysql": { "table": "supplierAddress" @@ -52,4 +47,4 @@ "foreignKey": "supplierFk" } } -} \ No newline at end of file +} diff --git a/modules/supplier/back/models/supplier-contact.json b/modules/supplier/back/models/supplier-contact.json index 9e13c33a8..f928cd204 100644 --- a/modules/supplier/back/models/supplier-contact.json +++ b/modules/supplier/back/models/supplier-contact.json @@ -1,10 +1,6 @@ { "name": "SupplierContact", "base": "Loggable", - "log": { - "model":"SupplierLog", - "relation": "supplier" - }, "options": { "mysql": { "table": "supplierContact" @@ -50,4 +46,4 @@ "permission": "ALLOW" } ] -} \ No newline at end of file +} diff --git a/modules/supplier/back/models/supplier.json b/modules/supplier/back/models/supplier.json index ee2c4fbbd..b6245ef32 100644 --- a/modules/supplier/back/models/supplier.json +++ b/modules/supplier/back/models/supplier.json @@ -1,9 +1,6 @@ { "name": "Supplier", "base": "Loggable", - "log": { - "model":"SupplierLog" - }, "options": { "mysql": { "table": "supplier" diff --git a/modules/supplier/front/agency-term/create/index.html b/modules/supplier/front/agency-term/create/index.html index 29d7b9b6a..728e98146 100644 --- a/modules/supplier/front/agency-term/create/index.html +++ b/modules/supplier/front/agency-term/create/index.html @@ -22,7 +22,7 @@ value-field="id" rule> - - - - - - - \ No newline at end of file + diff --git a/modules/supplier/front/agency-term/locale/es.yml b/modules/supplier/front/agency-term/locale/es.yml index f4ba7d87d..cdbd7c2ca 100644 --- a/modules/supplier/front/agency-term/locale/es.yml +++ b/modules/supplier/front/agency-term/locale/es.yml @@ -5,4 +5,5 @@ M3 Price: Precio M3 Route Price: Precio ruta Minimum Km: Km minimos Remove row: Eliminar fila -Add row: Añadir fila \ No newline at end of file +Add row: Añadir fila +New autonomous: Nuevo autónomo diff --git a/modules/supplier/front/create/index.html b/modules/supplier/front/create/index.html index 446a16cb6..c3efcf6ae 100644 --- a/modules/supplier/front/create/index.html +++ b/modules/supplier/front/create/index.html @@ -1,7 +1,8 @@ @@ -9,8 +10,8 @@ diff --git a/modules/ticket/back/methods/expedition/specs/deleteExpeditions.spec.js b/modules/ticket/back/methods/expedition/specs/deleteExpeditions.spec.js index 14bdf7aea..61937989e 100644 --- a/modules/ticket/back/methods/expedition/specs/deleteExpeditions.spec.js +++ b/modules/ticket/back/methods/expedition/specs/deleteExpeditions.spec.js @@ -1,6 +1,21 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('ticket deleteExpeditions()', () => { + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); + it('should delete the selected expeditions', async() => { const tx = await models.Expedition.beginTransaction({}); diff --git a/modules/ticket/back/methods/expedition/specs/moveExpeditions.spec.js b/modules/ticket/back/methods/expedition/specs/moveExpeditions.spec.js index ac397d38e..5f211543e 100644 --- a/modules/ticket/back/methods/expedition/specs/moveExpeditions.spec.js +++ b/modules/ticket/back/methods/expedition/specs/moveExpeditions.spec.js @@ -1,6 +1,21 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('ticket moveExpeditions()', () => { + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); + it('should move the selected expeditions to new ticket', async() => { const tx = await models.Expedition.beginTransaction({}); const ctx = { diff --git a/modules/ticket/back/methods/sale/specs/canEdit.spec.js b/modules/ticket/back/methods/sale/specs/canEdit.spec.js index a6c299321..62f98421a 100644 --- a/modules/ticket/back/methods/sale/specs/canEdit.spec.js +++ b/modules/ticket/back/methods/sale/specs/canEdit.spec.js @@ -1,7 +1,21 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('sale canEdit()', () => { const employeeId = 1; + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); describe('sale editTracked', () => { it('should return true if the role is production regardless of the saleTrackings', async() => { diff --git a/modules/ticket/back/methods/sale/specs/deleteSales.spec.js b/modules/ticket/back/methods/sale/specs/deleteSales.spec.js index 82cf916b3..3d3e06e22 100644 --- a/modules/ticket/back/methods/sale/specs/deleteSales.spec.js +++ b/modules/ticket/back/methods/sale/specs/deleteSales.spec.js @@ -1,6 +1,21 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('sale deleteSales()', () => { + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); + it('should throw an error if the ticket of the given sales is not editable', async() => { const tx = await models.Sale.beginTransaction({}); diff --git a/modules/ticket/back/methods/sale/specs/reserve.spec.js b/modules/ticket/back/methods/sale/specs/reserve.spec.js index 7ab79f9c0..259cb8cd5 100644 --- a/modules/ticket/back/methods/sale/specs/reserve.spec.js +++ b/modules/ticket/back/methods/sale/specs/reserve.spec.js @@ -1,4 +1,5 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('sale reserve()', () => { const ctx = { @@ -9,6 +10,20 @@ describe('sale reserve()', () => { } }; + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); + it('should throw an error if the ticket can not be modified', async() => { const tx = await models.Sale.beginTransaction({}); diff --git a/modules/ticket/back/methods/sale/specs/updateConcept.spec.js b/modules/ticket/back/methods/sale/specs/updateConcept.spec.js index 0e7e9bf0f..1b42e7140 100644 --- a/modules/ticket/back/methods/sale/specs/updateConcept.spec.js +++ b/modules/ticket/back/methods/sale/specs/updateConcept.spec.js @@ -1,6 +1,21 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('sale updateConcept()', () => { + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); + const ctx = {req: {accessToken: {userId: 9}}}; const saleId = 25; diff --git a/modules/ticket/back/methods/sale/specs/updatePrice.spec.js b/modules/ticket/back/methods/sale/specs/updatePrice.spec.js index 51cd2403f..133be8de3 100644 --- a/modules/ticket/back/methods/sale/specs/updatePrice.spec.js +++ b/modules/ticket/back/methods/sale/specs/updatePrice.spec.js @@ -1,6 +1,21 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('sale updatePrice()', () => { + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 18}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); + const ctx = { req: { accessToken: {userId: 18}, diff --git a/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js b/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js index 53a05cd7e..4778f6b6d 100644 --- a/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js +++ b/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js @@ -1,6 +1,21 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('sale updateQuantity()', () => { + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); + const ctx = { req: { accessToken: {userId: 9}, diff --git a/modules/ticket/back/methods/ticket-request/filter.js b/modules/ticket/back/methods/ticket-request/filter.js index 62c58ea95..921598b57 100644 --- a/modules/ticket/back/methods/ticket-request/filter.js +++ b/modules/ticket/back/methods/ticket-request/filter.js @@ -37,6 +37,10 @@ module.exports = Self => { type: 'number', description: `Search requests attended by a given worker id` }, + { + arg: 'requesterFk', + type: 'number' + }, { arg: 'mine', type: 'boolean', @@ -89,6 +93,8 @@ module.exports = Self => { return {'t.id': value}; case 'attenderFk': return {'tr.attenderFk': value}; + case 'requesterFk': + return {'tr.requesterFk': value}; case 'state': switch (value) { case 'pending': @@ -125,6 +131,7 @@ module.exports = Self => { tr.description, tr.response, tr.saleFk, + tr.requesterFk, tr.isOk, s.quantity AS saleQuantity, s.itemFk, diff --git a/modules/ticket/back/methods/ticket-request/specs/confirm.spec.js b/modules/ticket/back/methods/ticket-request/specs/confirm.spec.js index 49413cf44..de2817d87 100644 --- a/modules/ticket/back/methods/ticket-request/specs/confirm.spec.js +++ b/modules/ticket/back/methods/ticket-request/specs/confirm.spec.js @@ -1,6 +1,20 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('ticket-request confirm()', () => { + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); let ctx = { req: { accessToken: {userId: 9}, diff --git a/modules/ticket/back/methods/ticket-request/specs/deny.spec.js b/modules/ticket/back/methods/ticket-request/specs/deny.spec.js index 95fd0e84d..875a75921 100644 --- a/modules/ticket/back/methods/ticket-request/specs/deny.spec.js +++ b/modules/ticket/back/methods/ticket-request/specs/deny.spec.js @@ -1,6 +1,21 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('ticket-request deny()', () => { + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); + it('should return the denied ticket request', async() => { const tx = await models.TicketRequest.beginTransaction({}); diff --git a/modules/ticket/back/methods/ticket/closure.js b/modules/ticket/back/methods/ticket/closure.js index d5fa58e7b..9b3355d6c 100644 --- a/modules/ticket/back/methods/ticket/closure.js +++ b/modules/ticket/back/methods/ticket/closure.js @@ -46,7 +46,7 @@ module.exports = async function(Self, tickets, reqArgs = {}) { const fileName = `${year}${invoiceOut.ref}.pdf`; // Store invoice - storage.write(stream, { + await storage.write(stream, { type: 'invoice', path: `${year}/${month}/${day}`, fileName: fileName diff --git a/modules/ticket/back/methods/ticket/collectionLabel.js b/modules/ticket/back/methods/ticket/collectionLabel.js index 7601961fb..74b5b2c0a 100644 --- a/modules/ticket/back/methods/ticket/collectionLabel.js +++ b/modules/ticket/back/methods/ticket/collectionLabel.js @@ -1,5 +1,3 @@ -const {Report} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('collectionLabel', { description: 'Returns the collection label', @@ -39,17 +37,5 @@ module.exports = Self => { } }); - Self.collectionLabel = 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('collection-label', params); - const stream = await report.toPdfStream(); - - return [stream, 'application/pdf', `filename="doc-${id}.pdf"`]; - }; + Self.collectionLabel = (ctx, id) => Self.printReport(ctx, id, 'collection-label'); }; diff --git a/modules/ticket/back/methods/ticket/componentUpdate.js b/modules/ticket/back/methods/ticket/componentUpdate.js index 94b91e237..c23d1669e 100644 --- a/modules/ticket/back/methods/ticket/componentUpdate.js +++ b/modules/ticket/back/methods/ticket/componentUpdate.js @@ -165,18 +165,29 @@ module.exports = Self => { 'shipped', 'landed', 'isDeleted', - 'routeFk' + 'routeFk', + 'nickname' ], include: [ { relation: 'client', scope: { fields: 'salesPersonFk' - } - }] + }, + include: [ + { + relation: 'address', + scope: { + fields: 'nickname' + } + } + ] + }, + ] }, myOptions); args.routeFk = null; + if (args.isWithoutNegatives === false) delete args.isWithoutNegatives; const updatedTicket = Object.assign({}, args); delete updatedTicket.ctx; delete updatedTicket.option; @@ -224,37 +235,41 @@ module.exports = Self => { } const changes = loggable.getChanges(originalTicket, updatedTicket); - const oldProperties = await loggable.translateValues(Self, changes.old); - const newProperties = await loggable.translateValues(Self, changes.new); + const hasChanges = Object.keys(changes.old).length > 0 || Object.keys(changes.new).length > 0; - await models.TicketLog.create({ - originFk: args.id, - userFk: userId, - action: 'update', - changedModel: 'Ticket', - changedModelId: args.id, - oldInstance: oldProperties, - newInstance: newProperties - }, myOptions); + if (hasChanges) { + const oldProperties = await loggable.translateValues(Self, changes.old); + const newProperties = await loggable.translateValues(Self, changes.new); - const salesPersonId = originalTicket.client().salesPersonFk; - if (salesPersonId) { - const origin = ctx.req.headers.origin; + await models.TicketLog.create({ + originFk: args.id, + userFk: userId, + action: 'update', + changedModel: 'Ticket', + changedModelId: args.id, + oldInstance: oldProperties, + newInstance: newProperties + }, myOptions); - let changesMade = ''; - for (let change in newProperties) { - let value = newProperties[change]; - let oldValue = oldProperties[change]; + const salesPersonId = originalTicket.client().salesPersonFk; + if (salesPersonId) { + const origin = ctx.req.headers.origin; - changesMade += `\r\n~${$t(change)}: ${oldValue}~ ➔ *${$t(change)}: ${value}*`; + let changesMade = ''; + for (let change in newProperties) { + let value = newProperties[change]; + let oldValue = oldProperties[change]; + + changesMade += `\r\n~${$t(change)}: ${oldValue}~ ➔ *${$t(change)}: ${value}*`; + } + + const message = $t('Changed this data from the ticket', { + ticketId: args.id, + ticketUrl: `${origin}/#!/ticket/${args.id}/sale`, + changes: changesMade + }); + await models.Chat.sendCheckingPresence(ctx, salesPersonId, message); } - - const message = $t('Changed this data from the ticket', { - ticketId: args.id, - ticketUrl: `${origin}/#!/ticket/${args.id}/sale`, - changes: changesMade - }); - await models.Chat.sendCheckingPresence(ctx, salesPersonId, message); } res.id = args.id; diff --git a/modules/ticket/back/methods/ticket/deliveryNoteEmail.js b/modules/ticket/back/methods/ticket/deliveryNoteEmail.js index cf9f5dd62..4b275b45e 100644 --- a/modules/ticket/back/methods/ticket/deliveryNoteEmail.js +++ b/modules/ticket/back/methods/ticket/deliveryNoteEmail.js @@ -1,5 +1,3 @@ -const {Email} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('deliveryNoteEmail', { description: 'Sends the delivery note email with an attached PDF', @@ -47,19 +45,5 @@ module.exports = Self => { } }); - Self.deliveryNoteEmail = async ctx => { - 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('delivery-note', params); - - return email.send(); - }; + Self.deliveryNoteEmail = ctx => Self.sendTemplate(ctx, 'delivery-note'); }; diff --git a/modules/ticket/back/methods/ticket/deliveryNotePdf.js b/modules/ticket/back/methods/ticket/deliveryNotePdf.js index b2b3f7198..628e16bcd 100644 --- a/modules/ticket/back/methods/ticket/deliveryNotePdf.js +++ b/modules/ticket/back/methods/ticket/deliveryNotePdf.js @@ -1,5 +1,3 @@ -const {Report} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('deliveryNotePdf', { description: 'Returns the delivery note pdf', @@ -46,17 +44,5 @@ module.exports = Self => { } }); - Self.deliveryNotePdf = 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('delivery-note', params); - const stream = await report.toPdfStream(); - - return [stream, 'application/pdf', `filename="doc-${id}.pdf"`]; - }; + Self.deliveryNotePdf = (ctx, id) => Self.printReport(ctx, id, 'delivery-note'); }; diff --git a/modules/ticket/back/methods/ticket/expeditionPalletLabel.js b/modules/ticket/back/methods/ticket/expeditionPalletLabel.js index 2215263dd..9830364d6 100644 --- a/modules/ticket/back/methods/ticket/expeditionPalletLabel.js +++ b/modules/ticket/back/methods/ticket/expeditionPalletLabel.js @@ -1,5 +1,3 @@ -const {Report} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('expeditionPalletLabel', { description: 'Returns the expedition pallet label', @@ -39,17 +37,5 @@ module.exports = Self => { } }); - Self.expeditionPalletLabel = 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('expedition-pallet-label', params); - const stream = await report.toPdfStream(); - - return [stream, 'application/pdf', `filename="doc-${id}.pdf"`]; - }; + Self.expeditionPalletLabel = (ctx, id) => Self.printReport(ctx, id, 'expedition-pallet-label'); }; diff --git a/modules/ticket/back/methods/ticket/new.js b/modules/ticket/back/methods/ticket/new.js index 597ece3e5..a5d04bc4c 100644 --- a/modules/ticket/back/methods/ticket/new.js +++ b/modules/ticket/back/methods/ticket/new.js @@ -127,19 +127,6 @@ module.exports = Self => { ], myOptions); const ticket = await models.Ticket.findById(result[1][0].newTicketId, null, myOptions); - const cleanInstance = JSON.parse(JSON.stringify(ticket)); - - const logRecord = { - originFk: cleanInstance.id, - userFk: myUserId, - action: 'insert', - changedModel: 'Ticket', - changedModelId: cleanInstance.id, - oldInstance: {}, - newInstance: cleanInstance - }; - - await models.TicketLog.create(logRecord, myOptions); if (tx) await tx.commit(); diff --git a/modules/ticket/back/methods/ticket/saveSign.js b/modules/ticket/back/methods/ticket/saveSign.js new file mode 100644 index 000000000..39347f418 --- /dev/null +++ b/modules/ticket/back/methods/ticket/saveSign.js @@ -0,0 +1,139 @@ +const UserError = require('vn-loopback/util/user-error'); + +module.exports = Self => { + Self.remoteMethodCtx('saveSign', { + description: 'Save sign', + accessType: 'WRITE', + accepts: + [ + { + arg: 'tickets', + type: ['number'], + required: true, + description: 'The tickets' + }, + { + arg: 'location', + type: 'object', + description: 'The employee location the moment the sign is saved' + }, + { + arg: 'signedTime', + type: 'date', + description: 'The signed time' + } + ], + http: { + path: `/saveSign`, + verb: 'POST' + } + }); + + Self.saveSign = async(ctx, options) => { + const args = Object.assign({}, ctx.args); + const models = Self.app.models; + const myOptions = {}; + let tx; + let dms; + let gestDocCreated = false; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + if (!myOptions.transaction) { + tx = await Self.beginTransaction({}); + myOptions.transaction = tx; + } + + async function setLocation(ticketId) { + await models.Delivery.create({ + ticketFk: ticketId, + longitude: args.location.Longitude, + latitude: args.location.Latitude, + dated: args.signedTime || new Date() + }, myOptions); + } + + async function gestDocExists(ticketId) { + const ticketDms = await models.TicketDms.findOne({ + where: {ticketFk: ticketId}, + fields: ['dmsFk'] + }, myOptions); + + if (!ticketDms) return false; + + const ticket = await models.Ticket.findById(ticketId, {fields: ['isSigned']}, myOptions); + if (ticket.isSigned == true) + return true; + else + await models.Dms.destroyAll({where: {reference: ticketId}}, myOptions); + + return false; + } + + async function createGestDoc(id) { + const ticket = await models.Ticket.findById(id, + {include: [ + { + relation: 'warehouse', + scope: { + fields: ['id'] + } + }, { + relation: 'client', + scope: { + fields: ['name'] + } + }, { + relation: 'route', + scope: { + fields: ['id'] + } + } + ] + }, myOptions); + const dmsType = await models.DmsType.findOne({where: {code: 'Ticket'}, fields: ['id']}, myOptions); + const ctxUploadFile = Object.assign({}, ctx); + ctxUploadFile.args = { + warehouseId: ticket.warehouseFk, + companyId: ticket.companyFk, + dmsTypeId: dmsType.id, + reference: '', + description: `Firma del cliente - Ruta ${ticket.route().id}`, + hasFile: true + }; + dms = await models.Dms.uploadFile(ctxUploadFile, myOptions); + gestDocCreated = true; + } + + try { + for (let i = 0; i < args.tickets.length; i++) { + const ticketState = await models.TicketState.findOne( + {where: {ticketFk: args.tickets[i]}, + fields: ['alertLevel'] + }, myOptions); + + const packedAlertLevel = await models.AlertLevel.findOne({where: {code: 'PACKED'}, + fields: ['id'] + }, myOptions); + + if (ticketState.alertLevel < packedAlertLevel.id) + throw new UserError('This ticket cannot be signed because it has not been boxed'); + else if (!await gestDocExists(args.tickets[i])) { + if (args.location) setLocation(args.tickets[i]); + if (!gestDocCreated) await createGestDoc(args.tickets[i]); + await models.TicketDms.create({ticketFk: args.tickets[i], dmsFk: dms[0].id}, myOptions); + const ticket = await models.Ticket.findById(args.tickets[i], null, myOptions); + await ticket.updateAttribute('isSigned', true, myOptions); + await Self.rawSql(`CALL vn.ticket_setState(?, ?)`, [args.tickets[i], 'DELIVERED'], myOptions); + } + } + + if (tx) await tx.commit(); + return; + } catch (e) { + if (tx) await tx.rollback(); + throw e; + } + }; +}; diff --git a/modules/ticket/back/methods/ticket/specs/addSale.spec.js b/modules/ticket/back/methods/ticket/specs/addSale.spec.js index cfd149511..2e568716a 100644 --- a/modules/ticket/back/methods/ticket/specs/addSale.spec.js +++ b/modules/ticket/back/methods/ticket/specs/addSale.spec.js @@ -1,7 +1,21 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('ticket addSale()', () => { const ticketId = 13; + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); it('should create a new sale for the ticket with id 13', async() => { const tx = await models.Ticket.beginTransaction({}); diff --git a/modules/ticket/back/methods/ticket/specs/componentUpdate.spec.js b/modules/ticket/back/methods/ticket/specs/componentUpdate.spec.js index d65c87654..ef6422be2 100644 --- a/modules/ticket/back/methods/ticket/specs/componentUpdate.spec.js +++ b/modules/ticket/back/methods/ticket/specs/componentUpdate.spec.js @@ -17,6 +17,17 @@ describe('ticket componentUpdate()', () => { let componentValue; beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); const deliveryComponenet = await models.Component.findOne({where: {code: 'delivery'}}); deliveryComponentId = deliveryComponenet.id; componentOfSaleSeven = `SELECT value @@ -180,9 +191,6 @@ describe('ticket componentUpdate()', () => { } }; - spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ - active: ctx.req - }); const oldTicket = await models.Ticket.findById(ticketID, null, options); await models.Ticket.componentUpdate(ctx, options); diff --git a/modules/ticket/back/methods/ticket/specs/merge.spec.js b/modules/ticket/back/methods/ticket/specs/merge.spec.js index 6b533e47c..3254e58a8 100644 --- a/modules/ticket/back/methods/ticket/specs/merge.spec.js +++ b/modules/ticket/back/methods/ticket/specs/merge.spec.js @@ -2,19 +2,23 @@ const models = require('vn-loopback/server/server').models; const LoopBackContext = require('loopback-context'); describe('ticket merge()', () => { - const tickets = [{ + const tickets = { originId: 13, destinationId: 12, originShipped: Date.vnNew(), destinationShipped: Date.vnNew(), workerFk: 1 - }]; - - const activeCtx = { - accessToken: {userId: 9}, }; - beforeEach(() => { + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ active: activeCtx }); @@ -35,14 +39,14 @@ describe('ticket merge()', () => { try { const options = {transaction: tx}; - const chatNotificationBeforeMerge = await models.Chat.find(); + const chatNotificationBeforeMerge = await models.Chat.find(null, options); - await models.Ticket.merge(ctx, tickets, options); + await models.Ticket.merge(ctx, [tickets], options); - const createdTicketLog = await models.TicketLog.find({where: {originFk: tickets[0].originId}}, options); - const deletedTicket = await models.Ticket.findOne({where: {id: tickets[0].originId}}, options); - const salesTicketFuture = await models.Sale.find({where: {ticketFk: tickets[0].destinationId}}, options); - const chatNotificationAfterMerge = await models.Chat.find(); + const createdTicketLog = await models.TicketLog.find({where: {originFk: tickets.destinationId}}, options); + const deletedTicket = await models.Ticket.findOne({where: {id: tickets.originId}}, options); + const salesTicketFuture = await models.Sale.find({where: {ticketFk: tickets.destinationId}}, options); + const chatNotificationAfterMerge = await models.Chat.find(null, options); expect(createdTicketLog.length).toEqual(1); expect(deletedTicket.isDeleted).toEqual(true); diff --git a/modules/ticket/back/methods/ticket/specs/saveSign.spec.js b/modules/ticket/back/methods/ticket/specs/saveSign.spec.js new file mode 100644 index 000000000..6b532a5d1 --- /dev/null +++ b/modules/ticket/back/methods/ticket/specs/saveSign.spec.js @@ -0,0 +1,32 @@ +const models = require('vn-loopback/server/server').models; + +describe('Ticket saveSign()', () => { + const FormData = require('form-data'); + const data = new FormData(); + let ctx = {req: { + accessToken: {userId: 9}, + headers: { + ...data.getHeaders() + } + + }}; + + it(`should throw error if the ticket's alert level is lower than 2`, async() => { + const tx = await models.TicketDms.beginTransaction({}); + const ticketWithOkState = 12; + let error; + try { + const options = {transaction: tx}; + ctx.args = {tickets: [ticketWithOkState]}; + + await models.Ticket.saveSign(ctx, options); + + await tx.rollback(); + } catch (e) { + error = e; + await tx.rollback(); + } + + expect(error).toBeDefined(); + }); +}); diff --git a/modules/ticket/back/methods/ticket/specs/updateDiscount.spec.js b/modules/ticket/back/methods/ticket/specs/updateDiscount.spec.js index 1f6712087..41de1fd6e 100644 --- a/modules/ticket/back/methods/ticket/specs/updateDiscount.spec.js +++ b/modules/ticket/back/methods/ticket/specs/updateDiscount.spec.js @@ -1,6 +1,20 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('sale updateDiscount()', () => { + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); const originalSaleId = 8; it('should throw an error if no sales were selected', async() => { diff --git a/modules/ticket/back/methods/ticket/transferSales.js b/modules/ticket/back/methods/ticket/transferSales.js index 57f620f3d..48035648c 100644 --- a/modules/ticket/back/methods/ticket/transferSales.js +++ b/modules/ticket/back/methods/ticket/transferSales.js @@ -105,8 +105,8 @@ module.exports = Self => { originFk: id, userFk: userId, action: 'update', - changedModel: 'Ticket', - changedModelId: id, + changedModel: 'Sale', + changedModelId: sale.id, oldInstance: { item: originalSaleData.itemFk, quantity: originalSaleData.quantity, @@ -126,8 +126,8 @@ module.exports = Self => { originFk: ticketId, userFk: userId, action: 'update', - changedModel: 'Ticket', - changedModelId: ticketId, + changedModel: 'Sale', + changedModelId: sale.id, oldInstance: { item: originalSaleData.itemFk, quantity: originalSaleData.quantity, @@ -177,16 +177,16 @@ module.exports = Self => { // Update original sale const rest = originalSale.quantity - sale.quantity; - query = `UPDATE sale + query = `UPDATE sale SET quantity = ? WHERE id = ?`; await Self.rawSql(query, [rest, sale.id], options); // Clone sale with new quantity - query = `INSERT INTO sale (itemFk, ticketFk, concept, quantity, originalQuantity, price, discount, priceFixed, + query = `INSERT INTO sale (itemFk, ticketFk, concept, quantity, originalQuantity, price, discount, priceFixed, reserved, isPicked, isPriceFixed, isAdded) - SELECT itemFk, ?, concept, ?, originalQuantity, price, discount, priceFixed, - reserved, isPicked, isPriceFixed, isAdded + SELECT itemFk, ?, concept, ?, originalQuantity, price, discount, priceFixed, + reserved, isPicked, isPriceFixed, isAdded FROM sale WHERE id = ?`; await Self.rawSql(query, [ticketId, sale.quantity, sale.id], options); diff --git a/modules/ticket/back/models/expedition.json b/modules/ticket/back/models/expedition.json index d74c56d2c..e32a3b23d 100644 --- a/modules/ticket/back/models/expedition.json +++ b/modules/ticket/back/models/expedition.json @@ -1,10 +1,6 @@ { "name": "Expedition", "base": "Loggable", - "log": { - "model": "TicketLog", - "relation": "ticket" - }, "options": { "mysql": { "table": "expedition" @@ -59,4 +55,3 @@ } } } - \ No newline at end of file diff --git a/modules/ticket/back/models/sale.json b/modules/ticket/back/models/sale.json index 669b05be6..72ca1f5e0 100644 --- a/modules/ticket/back/models/sale.json +++ b/modules/ticket/back/models/sale.json @@ -1,11 +1,6 @@ { "name": "Sale", "base": "Loggable", - "log": { - "model": "TicketLog", - "relation": "ticket", - "showField": "concept" - }, "options": { "mysql": { "table": "sale" diff --git a/modules/ticket/back/models/specs/ticket-packaging.spec.js b/modules/ticket/back/models/specs/ticket-packaging.spec.js index f2834643d..6d59456a3 100644 --- a/modules/ticket/back/models/specs/ticket-packaging.spec.js +++ b/modules/ticket/back/models/specs/ticket-packaging.spec.js @@ -1,6 +1,20 @@ const app = require('vn-loopback/server/server'); +const LoopBackContext = require('loopback-context'); describe('ticket model TicketTracking', () => { + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); let ticketTrackingId; afterAll(async() => { diff --git a/modules/ticket/back/models/ticket-config.json b/modules/ticket/back/models/ticket-config.json index a1c96e7f6..d757fbd1a 100644 --- a/modules/ticket/back/models/ticket-config.json +++ b/modules/ticket/back/models/ticket-config.json @@ -14,6 +14,15 @@ }, "scopeDays": { "type": "number" + }, + "pickingDelay": { + "type": "number" + }, + "packagingInvoicingDated": { + "type": "date" + }, + "daysForWarningClaim": { + "type": "number" } } } diff --git a/modules/ticket/back/models/ticket-dms.json b/modules/ticket/back/models/ticket-dms.json index 8bcff254c..071999be7 100644 --- a/modules/ticket/back/models/ticket-dms.json +++ b/modules/ticket/back/models/ticket-dms.json @@ -1,10 +1,6 @@ { "name": "TicketDms", "base": "Loggable", - "log": { - "model": "TicketLog", - "relation": "ticket" - }, "options": { "mysql": { "table": "ticketDms" @@ -29,4 +25,4 @@ "foreignKey": "dmsFk" } } -} \ No newline at end of file +} diff --git a/modules/ticket/back/models/ticket-methods.js b/modules/ticket/back/models/ticket-methods.js index 73df0579c..3992e7307 100644 --- a/modules/ticket/back/models/ticket-methods.js +++ b/modules/ticket/back/models/ticket-methods.js @@ -39,4 +39,5 @@ module.exports = function(Self) { require('../methods/ticket/isRoleAdvanced')(Self); require('../methods/ticket/collectionLabel')(Self); require('../methods/ticket/expeditionPalletLabel')(Self); + require('../methods/ticket/saveSign')(Self); }; diff --git a/modules/ticket/back/models/ticket-observation.json b/modules/ticket/back/models/ticket-observation.json index 9035e4440..64e49b217 100644 --- a/modules/ticket/back/models/ticket-observation.json +++ b/modules/ticket/back/models/ticket-observation.json @@ -1,10 +1,6 @@ { "name": "TicketObservation", "base": "Loggable", - "log": { - "model": "TicketLog", - "relation": "ticket" - }, "options": { "mysql": { "table": "ticketObservation" diff --git a/modules/ticket/back/models/ticket-packaging.json b/modules/ticket/back/models/ticket-packaging.json index 533f4064c..6c94c810e 100644 --- a/modules/ticket/back/models/ticket-packaging.json +++ b/modules/ticket/back/models/ticket-packaging.json @@ -1,10 +1,6 @@ { "name": "TicketPackaging", "base": "Loggable", - "log": { - "model": "TicketLog", - "relation": "ticket" - }, "options": { "mysql": { "table": "ticketPackaging" diff --git a/modules/ticket/back/models/ticket-refund.json b/modules/ticket/back/models/ticket-refund.json index 8fd0e2306..d344a3f1c 100644 --- a/modules/ticket/back/models/ticket-refund.json +++ b/modules/ticket/back/models/ticket-refund.json @@ -6,10 +6,6 @@ "table": "ticketRefund" } }, - "log": { - "model": "TicketLog", - "relation": "originalTicket" - }, "properties": { "id": { "id": true, diff --git a/modules/ticket/back/models/ticket-request.json b/modules/ticket/back/models/ticket-request.json index 01601c7f6..f8407792e 100644 --- a/modules/ticket/back/models/ticket-request.json +++ b/modules/ticket/back/models/ticket-request.json @@ -1,10 +1,6 @@ { "name": "TicketRequest", "base": "Loggable", - "log": { - "model": "TicketLog", - "relation": "ticket" - }, "options": { "mysql": { "table": "ticketRequest" @@ -64,4 +60,4 @@ "foreignKey": "itemFk" } } -} \ No newline at end of file +} diff --git a/modules/ticket/back/models/ticket-service.json b/modules/ticket/back/models/ticket-service.json index 347b6b976..f1dbede13 100644 --- a/modules/ticket/back/models/ticket-service.json +++ b/modules/ticket/back/models/ticket-service.json @@ -1,11 +1,6 @@ { "name": "TicketService", "base": "Loggable", - "log": { - "model": "TicketLog", - "relation": "ticket", - "showField": "description" - }, "options": { "mysql": { "table": "ticketService" @@ -59,4 +54,4 @@ "foreignKey": "ticketServiceTypeFk" } } -} \ No newline at end of file +} diff --git a/modules/ticket/back/models/ticket-tracking.json b/modules/ticket/back/models/ticket-tracking.json index e80e2f8f4..8b5ce0b64 100644 --- a/modules/ticket/back/models/ticket-tracking.json +++ b/modules/ticket/back/models/ticket-tracking.json @@ -1,16 +1,11 @@ { "name": "TicketTracking", "base": "Loggable", - "log": { - "model": "TicketLog", - "relation": "ticket", - "showField": "stateFk" - }, - "options": { - "mysql": { - "table": "ticketTracking" - } - }, + "options": { + "mysql": { + "table": "ticketTracking" + } + }, "properties": { "id": { "id": true, @@ -48,4 +43,3 @@ } } } - \ No newline at end of file diff --git a/modules/ticket/back/models/ticket-weekly.json b/modules/ticket/back/models/ticket-weekly.json index d81baf4ad..c5e485aa2 100644 --- a/modules/ticket/back/models/ticket-weekly.json +++ b/modules/ticket/back/models/ticket-weekly.json @@ -1,11 +1,6 @@ { "name": "TicketWeekly", "base": "Loggable", - "log": { - "model": "TicketLog", - "relation": "ticket", - "showField": "ticketFk" - }, "options": { "mysql": { "table": "ticketWeekly" @@ -32,4 +27,4 @@ "foreignKey": "agencyModeFk" } } -} \ No newline at end of file +} diff --git a/modules/ticket/back/models/ticket.json b/modules/ticket/back/models/ticket.json index 09b01d213..b2e87362f 100644 --- a/modules/ticket/back/models/ticket.json +++ b/modules/ticket/back/models/ticket.json @@ -1,10 +1,6 @@ { "name": "Ticket", "base": "Loggable", - "log": { - "model":"TicketLog", - "showField": "id" - }, "options": { "mysql": { "table": "ticket" @@ -36,7 +32,7 @@ "type": "number" }, "updated": { - "type": "date", + "type": "date", "mysql": { "columnName": "created" } @@ -44,6 +40,9 @@ "isDeleted": { "type": "boolean" }, + "isSigned": { + "type": "boolean" + }, "priority": { "type": "number" }, @@ -136,4 +135,4 @@ "foreignKey": "zoneFk" } } -} \ No newline at end of file +} diff --git a/modules/ticket/front/expedition/locale/es.yml b/modules/ticket/front/expedition/locale/es.yml index 278dcc8f2..1933bac20 100644 --- a/modules/ticket/front/expedition/locale/es.yml +++ b/modules/ticket/front/expedition/locale/es.yml @@ -1,4 +1,4 @@ -Status log: Hitorial de estados +Status log: Historial de estados Expedition removed: Expedición eliminada Move: Mover New ticket without route: Nuevo ticket sin ruta diff --git a/modules/ticket/front/sale-tracking/index.html b/modules/ticket/front/sale-tracking/index.html index 33d22f92e..0309dde13 100644 --- a/modules/ticket/front/sale-tracking/index.html +++ b/modules/ticket/front/sale-tracking/index.html @@ -29,7 +29,7 @@ 'pink': sale.preparingList.hasSaleGroupDetail, 'none': !sale.preparingList.hasSaleGroupDetail, }" - class="circle" + class="circleState" vn-tooltip="has saleGroupDetail" > @@ -37,28 +37,28 @@ 'notice': sale.preparingList.isPreviousSelected, 'none': !sale.preparingList.isPreviousSelected, }" - class="circle" + class="circleState" vn-tooltip="is previousSelected"> diff --git a/modules/ticket/front/sale-tracking/style.scss b/modules/ticket/front/sale-tracking/style.scss index 1cc2f1b8c..78a0bda1d 100644 --- a/modules/ticket/front/sale-tracking/style.scss +++ b/modules/ticket/front/sale-tracking/style.scss @@ -1,6 +1,15 @@ @import "variables"; -.circle { +vn-sale-tracking { + .chip { + display: inline-block; + min-width: 15px; + min-height: 25px; + } + +} + +.circleState { display: inline-block; justify-content: center; align-items: center; diff --git a/modules/ticket/front/sale/index.html b/modules/ticket/front/sale/index.html index 8764417a8..6c37230ae 100644 --- a/modules/ticket/front/sale/index.html +++ b/modules/ticket/front/sale/index.html @@ -28,8 +28,9 @@ + disabled="!$ctrl.hasSelectedSales()" + vn-tooltip="Select lines to see the options" + ng-click="moreOptions.show($event)"> + + + Add claim + { + this.ticketConfig = res.data; + }); + } get isClaimable() { if (this.ticket) { @@ -184,6 +194,16 @@ class Controller extends Section { } createClaim() { + const timeDifference = new Date().getTime() - new Date(this.ticket.shipped).getTime(); + const pastDays = Math.floor(timeDifference / 86400000); + + if (pastDays >= this.ticketConfig[0].daysForWarningClaim) + this.$.claimConfirm.show(); + else + this.onCreateClaimAccepted(); + } + + onCreateClaimAccepted() { const sales = this.selectedValidSales(); const params = {ticketId: this.ticket.id, sales: sales}; this.resetChanges(); diff --git a/modules/ticket/front/sale/index.spec.js b/modules/ticket/front/sale/index.spec.js index 8585503cc..c35ed3d9a 100644 --- a/modules/ticket/front/sale/index.spec.js +++ b/modules/ticket/front/sale/index.spec.js @@ -45,6 +45,7 @@ describe('Ticket', () => { $scope.model = crudModel; $scope.editDiscount = {relocate: () => {}, hide: () => {}}; $scope.editPricePopover = {relocate: () => {}}; + $scope.claimConfirm = {show: () => {}}; $httpBackend = _$httpBackend_; Object.defineProperties($state.params, { id: { @@ -61,6 +62,10 @@ describe('Ticket', () => { controller.card = {reload: () => {}}; controller._ticket = ticket; controller._sales = sales; + controller.ticketConfig = [ + {daysForWarningClaim: 1} + ]; + $httpBackend.expect('GET', 'TicketConfigs').respond(200); })); describe('ticket() setter', () => { @@ -113,7 +118,6 @@ describe('Ticket', () => { it('should make an HTTP GET query and return the worker mana', () => { controller.edit = {}; const expectedAmount = 250; - $httpBackend.expect('GET', 'Tickets/1/getSalesPersonMana').respond(200, expectedAmount); $httpBackend.expect('GET', 'Sales/usesMana').respond(200); $httpBackend.expect('GET', 'WorkerManas/getCurrentWorkerMana').respond(200, expectedAmount); @@ -279,7 +283,17 @@ describe('Ticket', () => { }); describe('createClaim()', () => { - it('should perform a query and call windows open', () => { + it('should call to the claimConfirm show() method', () => { + jest.spyOn(controller.$.claimConfirm, 'show').mockReturnThis(); + + controller.createClaim(); + + expect(controller.$.claimConfirm.show).toHaveBeenCalledWith(); + }); + }); + + describe('onCreateClaimAccepted()', () => { + it('should perform a query and call window open', () => { jest.spyOn(controller, 'resetChanges').mockReturnThis(); jest.spyOn(controller.$state, 'go').mockReturnThis(); @@ -290,7 +304,7 @@ describe('Ticket', () => { const expectedParams = {ticketId: 1, sales: [firstSale]}; $httpBackend.expect('POST', `Claims/createFromSales`, expectedParams).respond(200, {id: 1}); - controller.createClaim(); + controller.onCreateClaimAccepted(); $httpBackend.flush(); expect(controller.resetChanges).toHaveBeenCalledWith(); diff --git a/modules/ticket/front/sale/locale/es.yml b/modules/ticket/front/sale/locale/es.yml index 2668b7811..bb61db824 100644 --- a/modules/ticket/front/sale/locale/es.yml +++ b/modules/ticket/front/sale/locale/es.yml @@ -40,3 +40,5 @@ Refund: Abono Promotion mana: Maná promoción Claim mana: Maná reclamación History: Historial +Do you want to continue?: ¿Desea continuar? +Claim out of time: Reclamación fuera de plazo diff --git a/modules/travel/back/methods/travel/extraCommunityEmail.js b/modules/travel/back/methods/travel/extraCommunityEmail.js index dd93ed905..f4b09b79d 100644 --- a/modules/travel/back/methods/travel/extraCommunityEmail.js +++ b/modules/travel/back/methods/travel/extraCommunityEmail.js @@ -1,5 +1,3 @@ -const {Email} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('extraCommunityEmail', { description: 'Sends the extra community email with an attached PDF', @@ -74,19 +72,5 @@ module.exports = Self => { } }); - Self.extraCommunityEmail = async ctx => { - 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('extra-community', params); - - return email.send(); - }; + Self.extraCommunityEmail = ctx => Self.sendTemplate(ctx, 'extra-community'); }; diff --git a/modules/travel/back/methods/travel/extraCommunityFilter.js b/modules/travel/back/methods/travel/extraCommunityFilter.js index 027261c4b..5ee51de8e 100644 --- a/modules/travel/back/methods/travel/extraCommunityFilter.js +++ b/modules/travel/back/methods/travel/extraCommunityFilter.js @@ -130,6 +130,7 @@ module.exports = Self => { SUM(b.stickers) AS stickers, s.id AS cargoSupplierFk, s.nickname AS cargoSupplierNickname, + s.name AS supplierName, CAST(SUM(b.weight * b.stickers) as DECIMAL(10,0)) as loadedKg, CAST(SUM(vc.aerealVolumetricDensity * b.stickers * IF(pkg.volume, pkg.volume, pkg.width * pkg.depth * pkg.height) / 1000000) as DECIMAL(10,0)) as volumeKg FROM travel t @@ -167,6 +168,7 @@ module.exports = Self => { SUM(b.stickers) AS stickers, e.evaNotes, e.notes, + e.invoiceAmount, CAST(SUM(b.weight * b.stickers) AS DECIMAL(10,0)) as loadedkg, CAST(SUM(vc.aerealVolumetricDensity * b.stickers * IF(pkg.volume, pkg.volume, pkg.width * pkg.depth * pkg.height) / 1000000) AS DECIMAL(10,0)) as volumeKg FROM tmp.travel tr diff --git a/modules/travel/back/methods/travel/extraCommunityPdf.js b/modules/travel/back/methods/travel/extraCommunityPdf.js index a68e5cd09..676b98be2 100644 --- a/modules/travel/back/methods/travel/extraCommunityPdf.js +++ b/modules/travel/back/methods/travel/extraCommunityPdf.js @@ -1,5 +1,3 @@ -const {Report} = require('vn-print'); - module.exports = Self => { Self.remoteMethodCtx('extraCommunityPdf', { description: 'Returns the extra community pdf', @@ -11,6 +9,16 @@ module.exports = Self => { description: 'The recipient id', required: false }, + { + arg: 'filter', + type: 'object', + description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string' + }, + { + arg: 'search', + type: 'string', + description: 'Searchs the travel by id' + }, { arg: 'landedTo', type: 'date' @@ -73,17 +81,5 @@ module.exports = Self => { } }); - Self.extraCommunityPdf = async ctx => { - 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('extra-community', params); - const stream = await report.toPdfStream(); - - return [stream, 'application/pdf', `filename="extra-community.pdf"`]; - }; + Self.extraCommunityPdf = ctx => Self.printReport(ctx, null, 'extra-community'); }; diff --git a/modules/travel/back/methods/travel/specs/createThermograph.spec.js b/modules/travel/back/methods/travel/specs/createThermograph.spec.js index 742e2dc18..e812eae70 100644 --- a/modules/travel/back/methods/travel/specs/createThermograph.spec.js +++ b/modules/travel/back/methods/travel/specs/createThermograph.spec.js @@ -1,6 +1,20 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('Travel createThermograph()', () => { + beforeAll(async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); const travelId = 3; const currentUserId = 1102; const thermographId = '138350-0'; diff --git a/modules/travel/back/models/travel-thermograph.json b/modules/travel/back/models/travel-thermograph.json index 754df1c3e..08eec2847 100644 --- a/modules/travel/back/models/travel-thermograph.json +++ b/modules/travel/back/models/travel-thermograph.json @@ -1,14 +1,9 @@ { "name": "TravelThermograph", "base": "Loggable", - "log": { - "model":"TravelLog", - "relation": "travel", - "showField": "ref" - }, "options": { "mysql": { - "table": "travelThermograph" + "table": "travelThermograph" } }, "properties": { diff --git a/modules/travel/back/models/travel.json b/modules/travel/back/models/travel.json index c20b7b0bf..95d458121 100644 --- a/modules/travel/back/models/travel.json +++ b/modules/travel/back/models/travel.json @@ -1,10 +1,6 @@ { "name": "Travel", "base": "Loggable", - "log": { - "model":"TravelLog", - "showField": "ref" - }, "options": { "mysql": { "table": "travel" diff --git a/modules/travel/front/extra-community/index.html b/modules/travel/front/extra-community/index.html index ee8dcdf98..c888f97da 100644 --- a/modules/travel/front/extra-community/index.html +++ b/modules/travel/front/extra-community/index.html @@ -1,9 +1,9 @@ @@ -48,6 +48,9 @@ Agency + Amount + Reference {{::travel.agencyModeName}} @@ -157,22 +161,15 @@ {{::entry.supplierName}} {{::entry.invoiceAmount | currency: 'EUR': 2}} {{::entry.ref}}{{::entry.invoiceNumber}} {{::entry.stickers}} {{::entry.loadedkg}} {{::entry.volumeKg}} - - {{::entry.notes}} - - - - {{::entry.evaNotes}} - -
{{entry.supplierName}} {{entry.reference}} {{entry.volumeKg | number($i18n.locale)}}{{entry.loadedKg | number($i18n.locale)}}{{entry.loadedkg | number($i18n.locale)}} {{entry.stickers}}
+<<<<<<< HEAD
+======= +
+>>>>>>> 2a8383f9ccaaa9c2dde10af42936f64de9436deb
{{$t('observations')}}
-
{{$t('wireTransfer')}}
-
{{$t('accountNumber', [invoice.iban])}}
+
+
{{$t('wireTransfer')}}
+
{{$t('accountNumber', [invoice.iban])}}
+
+
+ {{ticketObservations}} +
diff --git a/print/templates/reports/invoice/invoice.js b/print/templates/reports/invoice/invoice.js index a4d96edde..bfdf65564 100755 --- a/print/templates/reports/invoice/invoice.js +++ b/print/templates/reports/invoice/invoice.js @@ -11,12 +11,17 @@ module.exports = { this.client = await this.findOneFromDef('client', [this.reference]); this.taxes = await this.rawSqlFromDef(`taxes`, [this.reference]); this.hasIntrastat = await this.findValueFromDef(`hasIntrastat`, [this.reference]); +<<<<<<< HEAD this.intrastat = await this.rawSqlFromDef(`intrastat`, [ this.reference, this.reference, this.reference, this.reference ]); +======= + this.intrastat = await this.rawSqlFromDef(`intrastat`, + [this.reference, this.reference, this.reference, this.reference]); +>>>>>>> 2a8383f9ccaaa9c2dde10af42936f64de9436deb this.rectified = await this.rawSqlFromDef(`rectified`, [this.reference]); this.hasIncoterms = await this.findValueFromDef(`hasIncoterms`, [this.reference]); @@ -25,11 +30,15 @@ module.exports = { const map = new Map(); + this.ticketObservations = ''; for (let ticket of tickets) { ticket.sales = []; map.set(ticket.id, ticket); + + if (ticket.description) this.ticketObservations += ticket.description + ' '; } + this.ticketObservations = this.ticketObservations.trim(); for (let sale of sales) { const ticket = map.get(sale.ticketFk); diff --git a/print/templates/reports/invoice/sql/tickets.sql b/print/templates/reports/invoice/sql/tickets.sql index 162f043e2..a8385599c 100644 --- a/print/templates/reports/invoice/sql/tickets.sql +++ b/print/templates/reports/invoice/sql/tickets.sql @@ -1,8 +1,12 @@ SELECT t.id, t.shipped, - t.nickname -FROM invoiceOut io - JOIN ticket t ON t.refFk = io.ref + t.nickname, + tto.description +FROM invoiceOut io + JOIN ticket t ON t.refFk = io.REF + LEFT JOIN observationType ot ON ot.code = 'invoiceOut' + LEFT JOIN ticketObservation tto ON tto.ticketFk = t.id + AND tto.observationTypeFk = ot.id WHERE t.refFk = ? -ORDER BY t.shipped \ No newline at end of file +ORDER BY t.shipped