diff --git a/CHANGELOG.md b/CHANGELOG.md
index 93269cdb7..98815430e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- [General](Inicio) Permite recuperar la contraseña
+- [Ticket](Opciones) Subir albarán a Docuware
+- [Ticket](Opciones) Enviar correo con PDF de Docuware
- [Artículo](Datos Básicos) Añadido campo Unidades/Caja
### Changed
diff --git a/back/methods/docuware/checkFile.js b/back/methods/docuware/checkFile.js
index c6712bb65..c0a4e8ef3 100644
--- a/back/methods/docuware/checkFile.js
+++ b/back/methods/docuware/checkFile.js
@@ -1,4 +1,4 @@
-const got = require('got');
+const axios = require('axios');
module.exports = Self => {
Self.remoteMethodCtx('checkFile', {
@@ -8,7 +8,7 @@ module.exports = Self => {
{
arg: 'id',
type: 'number',
- description: 'The id',
+ description: 'The id',
http: {source: 'path'}
},
{
@@ -18,14 +18,14 @@ module.exports = Self => {
description: 'The fileCabinet name'
},
{
- arg: 'dialog',
- type: 'string',
+ arg: 'signed',
+ type: 'boolean',
required: true,
- description: 'The dialog name'
+ description: 'If pdf is necessary to be signed'
}
],
returns: {
- type: 'boolean',
+ type: 'object',
root: true
},
http: {
@@ -34,58 +34,51 @@ module.exports = Self => {
}
});
- Self.checkFile = async function(ctx, id, fileCabinet, dialog) {
- const myUserId = ctx.req.accessToken.userId;
- if (!myUserId)
- return false;
-
+ Self.checkFile = async function(ctx, id, fileCabinet, signed) {
const models = Self.app.models;
- const docuwareConfig = await models.DocuwareConfig.findOne();
+ const action = 'find';
+
const docuwareInfo = await models.Docuware.findOne({
where: {
code: fileCabinet,
- dialogName: dialog
+ action: action
}
});
- const docuwareUrl = docuwareConfig.url;
- const cookie = docuwareConfig.token;
- const fileCabinetName = docuwareInfo.fileCabinetName;
- const find = docuwareInfo.find;
- const options = {
- 'headers': {
- 'Accept': 'application/json',
- 'Content-Type': 'application/json',
- 'Cookie': cookie
- }
- };
const searchFilter = {
condition: [
{
- DBName: find,
+ DBName: docuwareInfo.findById,
+
Value: [id]
}
+ ],
+ sortOrder: [
+ {
+ Field: 'FILENAME',
+ Direction: 'Desc'
+ }
]
};
try {
- // get fileCabinetId
- const fileCabinetResponse = await got.get(`${docuwareUrl}/FileCabinets`, options);
- const fileCabinetJson = JSON.parse(fileCabinetResponse.body).FileCabinet;
- const fileCabinetId = fileCabinetJson.find(dialogs => dialogs.Name === fileCabinetName).Id;
+ const options = await Self.getOptions();
- // get dialog
- const dialogResponse = await got.get(`${docuwareUrl}/FileCabinets/${fileCabinetId}/dialogs`, options);
- const dialogJson = JSON.parse(dialogResponse.body).Dialog;
- const dialogId = dialogJson.find(dialogs => dialogs.DisplayName === 'find').Id;
+ const fileCabinetId = await Self.getFileCabinet(fileCabinet);
+ const dialogId = await Self.getDialog(fileCabinet, action, fileCabinetId);
- // get docuwareID
- Object.assign(options, {'body': JSON.stringify(searchFilter)});
- const response = await got.post(
- `${docuwareUrl}/FileCabinets/${fileCabinetId}/Query/DialogExpression?dialogId=${dialogId}`, options);
- JSON.parse(response.body).Items[0].Id;
+ const response = await axios.post(
+ `${options.url}/FileCabinets/${fileCabinetId}/Query/DialogExpression?dialogId=${dialogId}`,
+ searchFilter,
+ options.headers
+ );
+ const [documents] = response.data.Items;
+ if (!documents) return false;
- return true;
+ const state = documents.Fields.find(field => field.FieldName == 'ESTADO');
+ if (signed && state.Item != 'Firmado') return false;
+
+ return {id: documents.Id};
} catch (error) {
return false;
}
diff --git a/back/methods/docuware/core.js b/back/methods/docuware/core.js
new file mode 100644
index 000000000..2053ddf85
--- /dev/null
+++ b/back/methods/docuware/core.js
@@ -0,0 +1,78 @@
+const axios = require('axios');
+
+module.exports = Self => {
+ /**
+ * Returns the dialog id
+ *
+ * @param {string} code - The fileCabinet name
+ * @param {string} action - The fileCabinet name
+ * @param {string} fileCabinetId - Optional The fileCabinet name
+ * @return {number} - The fileCabinet id
+ */
+ Self.getDialog = async(code, action, fileCabinetId) => {
+ const docuwareInfo = await Self.app.models.Docuware.findOne({
+ where: {
+ code: code,
+ action: action
+ }
+ });
+ if (!fileCabinetId) fileCabinetId = await Self.getFileCabinet(code);
+
+ const options = await Self.getOptions();
+
+ if (!process.env.NODE_ENV)
+ return Math.round();
+
+ const response = await axios.get(`${options.url}/FileCabinets/${fileCabinetId}/dialogs`, options.headers);
+ const dialogs = response.data.Dialog;
+ const dialogId = dialogs.find(dialogs => dialogs.DisplayName === docuwareInfo.dialogName).Id;
+
+ return dialogId;
+ };
+
+ /**
+ * Returns the fileCabinetId
+ *
+ * @param {string} code - The fileCabinet code
+ * @return {number} - The fileCabinet id
+ */
+ Self.getFileCabinet = async code => {
+ const options = await Self.getOptions();
+ const docuwareInfo = await Self.app.models.Docuware.findOne({
+ where: {
+ code: code
+ }
+ });
+
+ if (!process.env.NODE_ENV)
+ return Math.round();
+
+ const fileCabinetResponse = await axios.get(`${options.url}/FileCabinets`, options.headers);
+ const fileCabinets = fileCabinetResponse.data.FileCabinet;
+ const fileCabinetId = fileCabinets.find(fileCabinet => fileCabinet.Name === docuwareInfo.fileCabinetName).Id;
+
+ return fileCabinetId;
+ };
+
+ /**
+ * Returns basic headers
+ *
+ * @param {string} cookie - The docuware cookie
+ * @return {object} - The headers
+ */
+ Self.getOptions = async() => {
+ const docuwareConfig = await Self.app.models.DocuwareConfig.findOne();
+ const headers = {
+ headers: {
+ 'Accept': 'application/json',
+ 'Content-Type': 'application/json',
+ 'Cookie': docuwareConfig.cookie
+ }
+ };
+
+ return {
+ url: docuwareConfig.url,
+ headers
+ };
+ };
+};
diff --git a/back/methods/docuware/deliveryNoteEmail.js b/back/methods/docuware/deliveryNoteEmail.js
new file mode 100644
index 000000000..1f9d7556f
--- /dev/null
+++ b/back/methods/docuware/deliveryNoteEmail.js
@@ -0,0 +1,72 @@
+const {Email} = require('vn-print');
+
+module.exports = Self => {
+ Self.remoteMethodCtx('deliveryNoteEmail', {
+ description: 'Sends the delivery note email with an docuware attached PDF',
+ accessType: 'WRITE',
+ accepts: [
+ {
+ arg: 'id',
+ type: 'string',
+ required: true,
+ description: 'The ticket id',
+ http: {source: 'path'}
+ },
+ {
+ arg: 'recipient',
+ type: 'string',
+ description: 'The recipient email',
+ required: true,
+ },
+ {
+ arg: 'recipientId',
+ type: 'number',
+ description: 'The client id',
+ required: false
+ }
+ ],
+ 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: '/:id/delivery-note-email',
+ verb: 'POST'
+ }
+ });
+
+ Self.deliveryNoteEmail = async(ctx, id) => {
+ 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);
+
+ const docuwareFile = await Self.app.models.Docuware.download(ctx, id, 'deliveryNote');
+
+ return email.send({
+ overrideAttachments: true,
+ attachments: [{
+ filename: `${id}.pdf`,
+ content: docuwareFile[0]
+ }]
+ });
+ };
+};
diff --git a/back/methods/docuware/download.js b/back/methods/docuware/download.js
index 489a07e34..56d006ee7 100644
--- a/back/methods/docuware/download.js
+++ b/back/methods/docuware/download.js
@@ -1,5 +1,5 @@
/* eslint max-len: ["error", { "code": 180 }]*/
-const got = require('got');
+const axios = require('axios');
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
@@ -10,19 +10,13 @@ module.exports = Self => {
{
arg: 'id',
type: 'number',
- description: 'The id',
+ description: 'The ticket id',
http: {source: 'path'}
},
{
arg: 'fileCabinet',
type: 'string',
- description: 'The id',
- http: {source: 'path'}
- },
- {
- arg: 'dialog',
- type: 'string',
- description: 'The id',
+ description: 'The file cabinet',
http: {source: 'path'}
}
],
@@ -42,79 +36,26 @@ module.exports = Self => {
}
],
http: {
- path: `/:id/download/:fileCabinet/:dialog`,
+ path: `/:id/download/:fileCabinet`,
verb: 'GET'
}
});
- Self.download = async function(ctx, id, fileCabinet, dialog) {
- const myUserId = ctx.req.accessToken.userId;
- if (!myUserId)
- throw new UserError(`You don't have enough privileges`);
-
+ Self.download = async function(ctx, id, fileCabinet) {
const models = Self.app.models;
- const docuwareConfig = await models.DocuwareConfig.findOne();
- const docuwareInfo = await models.Docuware.findOne({
- where: {
- code: fileCabinet,
- dialogName: dialog
- }
- });
+ const docuwareFile = await models.Docuware.checkFile(ctx, id, fileCabinet, true);
+ if (!docuwareFile) throw new UserError('The DOCUWARE PDF document does not exists');
- const docuwareUrl = docuwareConfig.url;
- const cookie = docuwareConfig.token;
- const fileCabinetName = docuwareInfo.fileCabinetName;
- const find = docuwareInfo.find;
- const options = {
- 'headers': {
- 'Accept': 'application/json',
- 'Content-Type': 'application/json',
- 'Cookie': cookie
- }
- };
- const searchFilter = {
- condition: [
- {
- DBName: find,
- Value: [id]
- }
- ]
- };
+ const fileCabinetId = await Self.getFileCabinet(fileCabinet);
+ const options = await Self.getOptions();
+ options.headers.responseType = 'stream';
- try {
- // get fileCabinetId
- const fileCabinetResponse = await got.get(`${docuwareUrl}/FileCabinets`, options);
- const fileCabinetJson = JSON.parse(fileCabinetResponse.body).FileCabinet;
- const fileCabinetId = fileCabinetJson.find(dialogs => dialogs.Name === fileCabinetName).Id;
+ const fileName = `filename="${id}.pdf"`;
+ const contentType = 'application/pdf';
+ const downloadUri = `${options.url}/FileCabinets/${fileCabinetId}/Documents/${docuwareFile.id}/FileDownload?targetFileType=Auto&keepAnnotations=false`;
- // get dialog
- const dialogResponse = await got.get(`${docuwareUrl}/FileCabinets/${fileCabinetId}/dialogs`, options);
- const dialogJson = JSON.parse(dialogResponse.body).Dialog;
- const dialogId = dialogJson.find(dialogs => dialogs.DisplayName === 'find').Id;
+ const stream = await axios.get(downloadUri, options.headers);
- // get docuwareID
- Object.assign(options, {'body': JSON.stringify(searchFilter)});
- const response = await got.post(`${docuwareUrl}/FileCabinets/${fileCabinetId}/Query/DialogExpression?dialogId=${dialogId}`, options);
- const docuwareId = JSON.parse(response.body).Items[0].Id;
-
- // download & save file
- const fileName = `filename="${id}.pdf"`;
- const contentType = 'application/pdf';
- const downloadUri = `${docuwareUrl}/FileCabinets/${fileCabinetId}/Documents/${docuwareId}/FileDownload?targetFileType=Auto&keepAnnotations=false`;
- const downloadOptions = {
- 'headers': {
- 'Cookie': cookie
- }
- };
-
- const stream = got.stream(downloadUri, downloadOptions);
-
- return [stream, contentType, fileName];
- } catch (error) {
- if (error.code === 'ENOENT')
- throw new UserError('The DOCUWARE PDF document does not exists');
-
- throw error;
- }
+ return [stream.data, contentType, fileName];
};
};
diff --git a/back/methods/docuware/specs/checkFile.spec.js b/back/methods/docuware/specs/checkFile.spec.js
index 0d0e4d71a..dd11951cc 100644
--- a/back/methods/docuware/specs/checkFile.spec.js
+++ b/back/methods/docuware/specs/checkFile.spec.js
@@ -1,5 +1,5 @@
const models = require('vn-loopback/server/server').models;
-const got = require('got');
+const axios = require('axios');
describe('docuware download()', () => {
const ticketId = 1;
@@ -12,53 +12,71 @@ describe('docuware download()', () => {
}
};
- const fileCabinetName = 'deliveryClient';
- const dialogDisplayName = 'find';
- const dialogName = 'findTicket';
+ const docuwareModel = models.Docuware;
+ const fileCabinetName = 'deliveryNote';
- const gotGetResponse = {
- body: JSON.stringify(
- {
- FileCabinet: [
- {Id: 12, Name: fileCabinetName}
- ],
- Dialog: [
- {Id: 34, DisplayName: dialogDisplayName}
- ]
- })
- };
-
- it('should return exist file in docuware', async() => {
- const gotPostResponse = {
- body: JSON.stringify(
- {
- Items: [
- {Id: 56}
- ],
- })
- };
-
- spyOn(got, 'get').and.returnValue(new Promise(resolve => resolve(gotGetResponse)));
- spyOn(got, 'post').and.returnValue(new Promise(resolve => resolve(gotPostResponse)));
-
- const result = await models.Docuware.checkFile(ctx, ticketId, fileCabinetName, dialogName);
-
- expect(result).toEqual(true);
+ beforeAll(() => {
+ spyOn(docuwareModel, 'getFileCabinet').and.returnValue((new Promise(resolve => resolve(Math.random()))));
+ spyOn(docuwareModel, 'getDialog').and.returnValue((new Promise(resolve => resolve(Math.random()))));
});
- it('should return not exist file in docuware', async() => {
- const gotPostResponse = {
- body: JSON.stringify(
- {
- Items: [],
- })
+ it('should return false if there are no documents', async() => {
+ const response = {
+ data: {
+ Items: []
+ }
};
+ spyOn(axios, 'post').and.returnValue(new Promise(resolve => resolve(response)));
- spyOn(got, 'get').and.returnValue(new Promise(resolve => resolve(gotGetResponse)));
- spyOn(got, 'post').and.returnValue(new Promise(resolve => resolve(gotPostResponse)));
-
- const result = await models.Docuware.checkFile(ctx, ticketId, fileCabinetName, dialogName);
+ const result = await models.Docuware.checkFile(ctx, ticketId, fileCabinetName, true);
expect(result).toEqual(false);
});
+
+ it('should return false if the document is unsigned', async() => {
+ const response = {
+ data: {
+ Items: [
+ {
+ Id: 1,
+ Fields: [
+ {
+ FieldName: 'ESTADO',
+ Item: 'Unsigned'
+ }
+ ]
+ }
+ ]
+ }
+ };
+ spyOn(axios, 'post').and.returnValue(new Promise(resolve => resolve(response)));
+
+ const result = await models.Docuware.checkFile(ctx, ticketId, fileCabinetName, true);
+
+ expect(result).toEqual(false);
+ });
+
+ it('should return the document data', async() => {
+ const docuwareId = 1;
+ const response = {
+ data: {
+ Items: [
+ {
+ Id: docuwareId,
+ Fields: [
+ {
+ FieldName: 'ESTADO',
+ Item: 'Firmado'
+ }
+ ]
+ }
+ ]
+ }
+ };
+ spyOn(axios, 'post').and.returnValue(new Promise(resolve => resolve(response)));
+
+ const result = await models.Docuware.checkFile(ctx, ticketId, fileCabinetName, true);
+
+ expect(result.id).toEqual(docuwareId);
+ });
});
diff --git a/back/methods/docuware/specs/download.spec.js b/back/methods/docuware/specs/download.spec.js
index dc80c67d8..fcc1671a6 100644
--- a/back/methods/docuware/specs/download.spec.js
+++ b/back/methods/docuware/specs/download.spec.js
@@ -1,5 +1,5 @@
const models = require('vn-loopback/server/server').models;
-const got = require('got');
+const axios = require('axios');
const stream = require('stream');
describe('docuware download()', () => {
@@ -13,36 +13,33 @@ describe('docuware download()', () => {
}
};
- it('should return the downloaded file name', async() => {
- const fileCabinetName = 'deliveryClient';
- const dialogDisplayName = 'find';
- const dialogName = 'findTicket';
- const gotGetResponse = {
- body: JSON.stringify(
- {
- FileCabinet: [
- {Id: 12, Name: fileCabinetName}
- ],
- Dialog: [
- {Id: 34, DisplayName: dialogDisplayName}
- ]
- })
- };
+ const docuwareModel = models.Docuware;
+ const fileCabinetName = 'deliveryNote';
- const gotPostResponse = {
- body: JSON.stringify(
- {
- Items: [
- {Id: 56}
- ],
- })
- };
+ beforeAll(() => {
+ spyOn(docuwareModel, 'getFileCabinet').and.returnValue((new Promise(resolve => resolve(Math.random()))));
+ spyOn(docuwareModel, 'getDialog').and.returnValue((new Promise(resolve => resolve(Math.random()))));
+ });
- spyOn(got, 'get').and.returnValue(new Promise(resolve => resolve(gotGetResponse)));
- spyOn(got, 'post').and.returnValue(new Promise(resolve => resolve(gotPostResponse)));
- spyOn(got, 'stream').and.returnValue(new stream.PassThrough({objectMode: true}));
+ it('should return error if file not exist', async() => {
+ spyOn(docuwareModel, 'checkFile').and.returnValue(false);
+ spyOn(axios, 'get').and.returnValue(new stream.PassThrough({objectMode: true}));
- const result = await models.Docuware.download(ctx, ticketId, fileCabinetName, dialogName);
+ let error;
+ try {
+ await models.Docuware.download(ctx, ticketId, fileCabinetName);
+ } catch (e) {
+ error = e.message;
+ }
+
+ expect(error).toEqual('The DOCUWARE PDF document does not exists');
+ });
+
+ it('should return the downloaded file if exist file ', async() => {
+ spyOn(docuwareModel, 'checkFile').and.returnValue({});
+ spyOn(axios, 'get').and.returnValue(new stream.PassThrough({objectMode: true}));
+
+ const result = await models.Docuware.download(ctx, ticketId, fileCabinetName);
expect(result[1]).toEqual('application/pdf');
expect(result[2]).toEqual(`filename="${ticketId}.pdf"`);
diff --git a/back/methods/docuware/specs/upload.spec.js b/back/methods/docuware/specs/upload.spec.js
new file mode 100644
index 000000000..7ac873e95
--- /dev/null
+++ b/back/methods/docuware/specs/upload.spec.js
@@ -0,0 +1,37 @@
+const models = require('vn-loopback/server/server').models;
+
+describe('docuware upload()', () => {
+ const userId = 9;
+ const ticketId = 10;
+ const ctx = {
+ req: {
+ getLocale: () => {
+ return 'en';
+ },
+ accessToken: {userId: userId},
+ headers: {origin: 'http://localhost:5000'},
+ }
+ };
+
+ const docuwareModel = models.Docuware;
+ const ticketModel = models.Ticket;
+ const fileCabinetName = 'deliveryNote';
+
+ beforeAll(() => {
+ spyOn(docuwareModel, 'getFileCabinet').and.returnValue(new Promise(resolve => resolve(Math.random())));
+ spyOn(docuwareModel, 'getDialog').and.returnValue(new Promise(resolve => resolve(Math.random())));
+ });
+
+ it('should try upload file', async() => {
+ spyOn(ticketModel, 'deliveryNotePdf').and.returnValue(new Promise(resolve => resolve({})));
+
+ let error;
+ try {
+ await models.Docuware.upload(ctx, ticketId, fileCabinetName);
+ } catch (e) {
+ error = e.message;
+ }
+
+ expect(error).toEqual('Action not allowed on the test environment');
+ });
+});
diff --git a/back/methods/docuware/upload.js b/back/methods/docuware/upload.js
new file mode 100644
index 000000000..b5ee3d18f
--- /dev/null
+++ b/back/methods/docuware/upload.js
@@ -0,0 +1,141 @@
+const UserError = require('vn-loopback/util/user-error');
+const axios = require('axios');
+
+module.exports = Self => {
+ Self.remoteMethodCtx('upload', {
+ description: 'Upload an docuware PDF',
+ accessType: 'WRITE',
+ accepts: [
+ {
+ arg: 'id',
+ type: 'number',
+ description: 'The ticket id',
+ http: {source: 'path'}
+ },
+ {
+ arg: 'fileCabinet',
+ type: 'string',
+ description: 'The file cabinet'
+ },
+ {
+ arg: 'dialog',
+ type: 'string',
+ description: 'The dialog'
+ }
+ ],
+ returns: [],
+ http: {
+ path: `/:id/upload`,
+ verb: 'POST'
+ }
+ });
+
+ Self.upload = async function(ctx, id, fileCabinet) {
+ const models = Self.app.models;
+ const action = 'store';
+
+ const options = await Self.getOptions();
+ const fileCabinetId = await Self.getFileCabinet(fileCabinet);
+ const dialogId = await Self.getDialog(fileCabinet, action, fileCabinetId);
+
+ // get delivery note
+ const deliveryNote = await models.Ticket.deliveryNotePdf(ctx, {
+ id,
+ type: 'deliveryNote'
+ });
+
+ // get ticket data
+ const ticket = await models.Ticket.findById(id, {
+ include: [{
+ relation: 'client',
+ scope: {
+ fields: ['id', 'socialName', 'fi']
+ }
+ }]
+ });
+
+ // upload file
+ const templateJson = {
+ 'Fields': [
+ {
+ 'FieldName': 'N__ALBAR_N',
+ 'ItemElementName': 'string',
+ 'Item': id,
+ },
+ {
+ 'FieldName': 'CIF_PROVEEDOR',
+ 'ItemElementName': 'string',
+ 'Item': ticket.client().fi,
+ },
+ {
+ 'FieldName': 'CODIGO_PROVEEDOR',
+ 'ItemElementName': 'string',
+ 'Item': ticket.client().id,
+ },
+ {
+ 'FieldName': 'NOMBRE_PROVEEDOR',
+ 'ItemElementName': 'string',
+ 'Item': ticket.client().socialName,
+ },
+ {
+ 'FieldName': 'FECHA_FACTURA',
+ 'ItemElementName': 'date',
+ 'Item': ticket.shipped,
+ },
+ {
+ 'FieldName': 'TOTAL_FACTURA',
+ 'ItemElementName': 'Decimal',
+ 'Item': ticket.totalWithVat,
+ },
+ {
+ 'FieldName': 'ESTADO',
+ 'ItemElementName': 'string',
+ 'Item': 'Pendiente procesar',
+ },
+ {
+ 'FieldName': 'FIRMA_',
+ 'ItemElementName': 'string',
+ 'Item': 'Si',
+ },
+ {
+ 'FieldName': 'FILTRO_TABLET',
+ 'ItemElementName': 'string',
+ 'Item': 'Tablet1',
+ }
+ ]
+ };
+
+ if (process.env.NODE_ENV != 'production')
+ throw new UserError('Action not allowed on the test environment');
+
+ // delete old
+ const docuwareFile = await models.Docuware.checkFile(ctx, id, fileCabinet, false);
+ if (docuwareFile) {
+ const deleteJson = {
+ 'Field': [{'FieldName': 'ESTADO', 'Item': 'Pendiente eliminar', 'ItemElementName': 'String'}]
+ };
+ const deleteUri = `${options.url}/FileCabinets/${fileCabinetId}/Documents/${docuwareFile.id}/Fields`;
+ await axios.put(deleteUri, deleteJson, options.headers);
+ }
+
+ const uploadUri = `${options.url}/FileCabinets/${fileCabinetId}/Documents?StoreDialogId=${dialogId}`;
+ const FormData = require('form-data');
+ const data = new FormData();
+
+ data.append('document', JSON.stringify(templateJson), 'schema.json');
+ data.append('file[]', deliveryNote[0], 'file.pdf');
+ const uploadOptions = {
+ headers: {
+ 'Content-Type': 'multipart/form-data',
+ 'X-File-ModifiedDate': new Date(),
+ 'Cookie': options.headers.headers.Cookie,
+ ...data.getHeaders()
+ },
+ };
+
+ return await axios.post(uploadUri, data, uploadOptions)
+ .catch(() => {
+ throw new UserError('Failed to upload file');
+ });
+ };
+};
diff --git a/back/models/docuware-config.json b/back/models/docuware-config.json
index 8ca76d8ba..9d06c4874 100644
--- a/back/models/docuware-config.json
+++ b/back/models/docuware-config.json
@@ -16,7 +16,7 @@
"url": {
"type": "string"
},
- "token": {
+ "cookie": {
"type": "string"
}
},
@@ -29,4 +29,4 @@
"permission": "ALLOW"
}
]
-}
\ No newline at end of file
+}
diff --git a/back/models/docuware.js b/back/models/docuware.js
index 8fd8065ed..b983f7bb4 100644
--- a/back/models/docuware.js
+++ b/back/models/docuware.js
@@ -1,4 +1,7 @@
module.exports = Self => {
require('../methods/docuware/download')(Self);
+ require('../methods/docuware/upload')(Self);
require('../methods/docuware/checkFile')(Self);
+ require('../methods/docuware/deliveryNoteEmail')(Self);
+ require('../methods/docuware/core')(Self);
};
diff --git a/back/models/docuware.json b/back/models/docuware.json
index fb2ed919e..dec20eede 100644
--- a/back/models/docuware.json
+++ b/back/models/docuware.json
@@ -19,20 +19,14 @@
"fileCabinetName": {
"type": "string"
},
+ "action": {
+ "type": "string"
+ },
"dialogName": {
"type": "string"
},
- "find": {
+ "findById": {
"type": "string"
}
- },
- "acls": [
- {
- "property": "*",
- "accessType": "*",
- "principalType": "ROLE",
- "principalId": "$everyone",
- "permission": "ALLOW"
- }
- ]
-}
\ No newline at end of file
+ }
+}
diff --git a/db/changes/230201/00-docuwareStore.sql b/db/changes/230201/00-docuwareStore.sql
new file mode 100644
index 000000000..b20c2554f
--- /dev/null
+++ b/db/changes/230201/00-docuwareStore.sql
@@ -0,0 +1,23 @@
+CREATE OR REPLACE TABLE `vn`.`docuware` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `code` varchar(50) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `fileCabinetName` varchar(50) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `action` varchar(255) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `dialogName` varchar(100) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `findById` varchar(50) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
+
+INSERT INTO `vn`.`docuware` (`code`, `fileCabinetName`, `action`, `dialogName`, `findById`)
+ VALUES
+ ('deliveryNote', 'Albaranes cliente', 'find', 'find', 'N__ALBAR_N'),
+ ('deliveryNote', 'Albaranes cliente', 'store', 'Archivar', 'N__ALBAR_N');
+
+INSERT INTO `salix`.`ACL` (`model`,`property`,`accessType`,`permission`,`principalId`)
+ VALUES
+ ('Docuware','checkFile','READ','ALLOW','employee'),
+ ('Docuware','download','READ','ALLOW','salesPerson'),
+ ('Docuware','upload','WRITE','ALLOW','productionAssi'),
+ ('Docuware','deliveryNoteEmail','WRITE','ALLOW','salesPerson');
+
+ALTER TABLE `vn`.`docuwareConfig` CHANGE token cookie varchar(1000) CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci DEFAULT NULL NULL;
diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql
index c10649ff3..fba094ef4 100644
--- a/db/dump/fixtures.sql
+++ b/db/dump/fixtures.sql
@@ -2580,13 +2580,9 @@ INSERT INTO `bs`.`sale` (`saleFk`, `amount`, `dated`, `typeFk`, `clientFk`)
(4, 33.8, util.VN_CURDATE(), 1, 1101),
(30, 34.4, util.VN_CURDATE(), 1, 1108);
-INSERT INTO `vn`.`docuware` (`code`, `fileCabinetName`, `dialogName` , `find`)
- VALUES
- ('deliveryClient', 'deliveryClient', 'findTicket', 'word');
-
INSERT INTO `vn`.`docuwareConfig` (`url`)
VALUES
- ('https://verdnatura.docuware.cloud/docuware/platform');
+ ('http://docuware.url/');
INSERT INTO `vn`.`calendarHolidaysName` (`id`, `name`)
VALUES
diff --git a/db/export-data.sh b/db/export-data.sh
index 8bff538a7..bdf8049e0 100755
--- a/db/export-data.sh
+++ b/db/export-data.sh
@@ -59,6 +59,7 @@ TABLES=(
componentType
continent
department
+ docuware
itemPackingType
pgc
sample
diff --git a/loopback/locale/es.json b/loopback/locale/es.json
index ea83b36c4..f6f305dc3 100644
--- a/loopback/locale/es.json
+++ b/loopback/locale/es.json
@@ -135,7 +135,7 @@
"Changed client paymethod": "He cambiado la forma de pago del cliente [{{clientName}} ({{clientId}})]({{{url}}})",
"Sent units from ticket": "Envio *{{quantity}}* unidades de [{{concept}} ({{itemId}})]({{{itemUrl}}}) a *\"{{nickname}}\"* provenientes del ticket id [{{ticketId}}]({{{ticketUrl}}})",
"Change quantity": "{{concept}} cambia de {{oldQuantity}} a {{newQuantity}}",
- "Claim will be picked": "Se recogerá el género de la reclamación [({{claimId}})]({{{claimUrl}}}) del cliente *{{clientName}}*",
+ "Claim will be picked": "Se recogerá el género de la reclamación [({{claimId}})]({{{claimUrl}}}) del cliente *{{clientName}}*",
"Claim state has changed to incomplete": "Se ha cambiado el estado de la reclamación [({{claimId}})]({{{claimUrl}}}) del cliente *{{clientName}}* a *incompleta*",
"Claim state has changed to canceled": "Se ha cambiado el estado de la reclamación [({{claimId}})]({{{claimUrl}}}) del cliente *{{clientName}}* a *anulado*",
"Client checked as validated despite of duplication": "Cliente comprobado a pesar de que existe el cliente id {{clientId}}",
@@ -252,5 +252,9 @@
"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",
- "Aplicación bloqueada por el usuario 9": "Aplicación bloqueada por el usuario 9"
+ "App name does not exist": "El nombre de aplicación no es válido",
+ "Try again": "Vuelve a intentarlo",
+ "Aplicación bloqueada por el usuario 9": "Aplicación bloqueada por el usuario 9",
+ "Failed to upload file": "Error al subir archivo",
+ "The DOCUWARE PDF document does not exists": "The DOCUWARE PDF document does not exists"
}
\ No newline at end of file
diff --git a/modules/invoiceOut/back/methods/invoiceOut/specs/createPdf.spec.js b/modules/invoiceOut/back/methods/invoiceOut/specs/createPdf.spec.js
index 803338ef3..26eae45ac 100644
--- a/modules/invoiceOut/back/methods/invoiceOut/specs/createPdf.spec.js
+++ b/modules/invoiceOut/back/methods/invoiceOut/specs/createPdf.spec.js
@@ -11,6 +11,7 @@ describe('InvoiceOut createPdf()', () => {
const ctx = {req: activeCtx};
it('should create a new PDF file and set true the hasPdf property', async() => {
+ pending('https://redmine.verdnatura.es/issues/5035');
const invoiceId = 1;
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
diff --git a/modules/mdb/back/methods/mdbVersion/last.js b/modules/mdb/back/methods/mdbVersion/last.js
new file mode 100644
index 000000000..5f89f10fb
--- /dev/null
+++ b/modules/mdb/back/methods/mdbVersion/last.js
@@ -0,0 +1,46 @@
+const UserError = require('vn-loopback/util/user-error');
+
+module.exports = Self => {
+ Self.remoteMethodCtx('last', {
+ description: 'Gets the latest version of a access file',
+ accepts: [
+ {
+ arg: 'appName',
+ type: 'string',
+ required: true,
+ description: 'The app name'
+ }
+ ],
+ returns: {
+ type: 'number',
+ root: true
+ },
+ http: {
+ path: `/:appName/last`,
+ verb: 'GET'
+ }
+ });
+
+ Self.last = async(ctx, appName) => {
+ const models = Self.app.models;
+ const versions = await models.MdbVersion.find({
+ where: {app: appName},
+ fields: ['version']
+ });
+
+ if (!versions.length)
+ throw new UserError('App name does not exist');
+
+ let maxNumber = 0;
+ for (let mdb of versions) {
+ if (mdb.version > maxNumber)
+ maxNumber = mdb.version;
+ }
+
+ let response = {
+ version: maxNumber
+ };
+
+ return response;
+ };
+};
diff --git a/modules/mdb/back/methods/mdbVersion/upload.js b/modules/mdb/back/methods/mdbVersion/upload.js
index ea88c58f7..1df4365a9 100644
--- a/modules/mdb/back/methods/mdbVersion/upload.js
+++ b/modules/mdb/back/methods/mdbVersion/upload.js
@@ -11,20 +11,22 @@ module.exports = Self => {
type: 'string',
required: true,
description: 'The app name'
- },
- {
- arg: 'newVersion',
+ }, {
+ arg: 'toVersion',
type: 'number',
required: true,
description: `The new version number`
- },
- {
+ }, {
arg: 'branch',
type: 'string',
required: true,
description: `The branch name`
- },
- {
+ }, {
+ arg: 'fromVersion',
+ type: 'string',
+ required: true,
+ description: `The old version number`
+ }, {
arg: 'unlock',
type: 'boolean',
required: false,
@@ -41,16 +43,13 @@ module.exports = Self => {
}
});
- Self.upload = async(ctx, appName, newVersion, branch, unlock, options) => {
+ Self.upload = async(ctx, appName, toVersion, branch, fromVersion, unlock, options) => {
const models = Self.app.models;
- const userId = ctx.req.accessToken.userId;
const myOptions = {};
const $t = ctx.req.__; // $translate
-
const TempContainer = models.TempContainer;
const AccessContainer = models.AccessContainer;
const fileOptions = {};
-
let tx;
if (typeof options == 'object')
@@ -63,6 +62,7 @@ module.exports = Self => {
let srcFile;
try {
+ const userId = ctx.req.accessToken.userId;
const mdbApp = await models.MdbApp.findById(appName, null, myOptions);
if (mdbApp && mdbApp.locked && mdbApp.userFk != userId) {
@@ -71,6 +71,19 @@ module.exports = Self => {
}));
}
+ const existBranch = await models.MdbBranch.findOne({
+ where: {name: branch}
+ }, myOptions);
+
+ if (!existBranch)
+ throw new UserError('Not exist this branch');
+
+ let lastMethod = await Self.last(ctx, appName, myOptions);
+ lastMethod.version++;
+
+ if (lastMethod.version != toVersion)
+ throw new UserError('Try again');
+
const tempContainer = await TempContainer.container('access');
const uploaded = await TempContainer.upload(tempContainer.name, ctx.req, ctx.result, fileOptions);
const files = Object.values(uploaded.files).map(file => {
@@ -83,7 +96,7 @@ module.exports = Self => {
const accessContainer = await AccessContainer.container('.archive');
const destinationFile = path.join(
- accessContainer.client.root, accessContainer.name, appName, `${newVersion}.7z`);
+ accessContainer.client.root, accessContainer.name, appName, `${toVersion}.7z`);
if (process.env.NODE_ENV == 'test')
await fs.unlink(srcFile);
@@ -104,7 +117,7 @@ module.exports = Self => {
await fs.mkdir(branchPath, {recursive: true});
const destinationBranch = path.join(branchPath, `${appName}.7z`);
- const destinationRelative = `../../.archive/${appName}/${newVersion}.7z`;
+ const destinationRelative = `../../.archive/${appName}/${toVersion}.7z`;
try {
await fs.unlink(destinationBranch);
} catch (e) {}
@@ -112,7 +125,7 @@ module.exports = Self => {
if (branch == 'master') {
const destinationRoot = path.join(accessContainer.client.root, `${appName}.7z`);
- const rootRelative = `./.archive/${appName}/${newVersion}.7z`;
+ const rootRelative = `./.archive/${appName}/${toVersion}.7z`;
try {
await fs.unlink(destinationRoot);
} catch (e) {}
@@ -120,10 +133,18 @@ module.exports = Self => {
}
}
+ await models.MdbVersionTree.create({
+ app: appName,
+ version: toVersion,
+ branchFk: branch,
+ fromVersion,
+ userFk: userId
+ }, myOptions);
+
await models.MdbVersion.upsert({
app: appName,
branchFk: branch,
- version: newVersion
+ version: toVersion
}, myOptions);
if (unlock) await models.MdbApp.unlock(ctx, appName, myOptions);
@@ -133,7 +154,7 @@ module.exports = Self => {
if (tx) await tx.rollback();
if (fs.existsSync(srcFile))
- await fs.unlink(srcFile);
+ fs.unlink(srcFile);
throw e;
}
diff --git a/modules/mdb/back/model-config.json b/modules/mdb/back/model-config.json
index 6107f8790..8010afca2 100644
--- a/modules/mdb/back/model-config.json
+++ b/modules/mdb/back/model-config.json
@@ -8,6 +8,9 @@
"MdbVersion": {
"dataSource": "vn"
},
+ "MdbVersionTree": {
+ "dataSource": "vn"
+ },
"AccessContainer": {
"dataSource": "accessStorage"
}
diff --git a/modules/mdb/back/models/mdbVersion.js b/modules/mdb/back/models/mdbVersion.js
index b36ee2a60..3a7a0c6f3 100644
--- a/modules/mdb/back/models/mdbVersion.js
+++ b/modules/mdb/back/models/mdbVersion.js
@@ -1,3 +1,4 @@
module.exports = Self => {
require('../methods/mdbVersion/upload')(Self);
+ require('../methods/mdbVersion/last')(Self);
};
diff --git a/modules/mdb/back/models/mdbVersionTree.json b/modules/mdb/back/models/mdbVersionTree.json
new file mode 100644
index 000000000..8c0260e54
--- /dev/null
+++ b/modules/mdb/back/models/mdbVersionTree.json
@@ -0,0 +1,35 @@
+{
+ "name": "MdbVersionTree",
+ "base": "VnModel",
+ "options": {
+ "mysql": {
+ "table": "mdbVersionTree"
+ }
+ },
+ "properties": {
+ "app": {
+ "type": "string",
+ "description": "The app name",
+ "id": true
+ },
+ "version": {
+ "type": "number"
+ },
+ "branchFk": {
+ "type": "string"
+ },
+ "fromVersion": {
+ "type": "number"
+ },
+ "userFk": {
+ "type": "number"
+ }
+ },
+ "relations": {
+ "branch": {
+ "type": "belongsTo",
+ "model": "MdbBranch",
+ "foreignKey": "branchFk"
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/ticket/front/descriptor-menu/index.html b/modules/ticket/front/descriptor-menu/index.html
index 805e0b391..c2ebc3e3a 100644
--- a/modules/ticket/front/descriptor-menu/index.html
+++ b/modules/ticket/front/descriptor-menu/index.html
@@ -21,30 +21,28 @@
Add turn
Show Delivery Note...
as PDF
-
- as PDF
-
as PDF without prices
+
+ as PDF signed
+
@@ -54,7 +52,7 @@
Send Delivery Note...
@@ -64,6 +62,11 @@
translate>
Send PDF
+
+ Send PDF to tablet
+
@@ -323,3 +326,18 @@
question="Are you sure you want to refund all?"
message="Refund all">
+
+
+
+
+
+
+
+
diff --git a/modules/ticket/front/descriptor-menu/index.js b/modules/ticket/front/descriptor-menu/index.js
index b9b4519b9..f6001c6b8 100644
--- a/modules/ticket/front/descriptor-menu/index.js
+++ b/modules/ticket/front/descriptor-menu/index.js
@@ -85,7 +85,6 @@ class Controller extends Section {
.then(res => this.ticket = res.data)
.then(() => {
this.isTicketEditable();
- this.hasDocuware();
});
}
@@ -134,15 +133,6 @@ class Controller extends Section {
});
}
- hasDocuware() {
- const params = {
- fileCabinet: 'deliveryClient',
- dialog: 'findTicket'
- };
- this.$http.post(`Docuwares/${this.id}/checkFile`, params)
- .then(res => this.hasDocuwareFile = res.data);
- }
-
showPdfDeliveryNote(type) {
this.vnReport.show(`tickets/${this.id}/delivery-note-pdf`, {
recipientId: this.ticket.client.id,
@@ -151,7 +141,10 @@ class Controller extends Section {
}
sendPdfDeliveryNote($data) {
- return this.vnEmail.send(`tickets/${this.id}/delivery-note-email`, {
+ let query = `tickets/${this.id}/delivery-note-email`;
+ if (this.hasDocuwareFile) query = `docuwares/${this.id}/delivery-note-email`;
+
+ return this.vnEmail.send(query, {
recipientId: this.ticket.client.id,
recipient: $data.email
});
@@ -319,6 +312,24 @@ class Controller extends Section {
return this.$http.post(`Tickets/${this.id}/sendSms`, sms)
.then(() => this.vnApp.showSuccess(this.$t('SMS sent')));
}
+
+ hasDocuware() {
+ this.$http.post(`Docuwares/${this.id}/checkFile`, {fileCabinet: 'deliveryNote', signed: true})
+ .then(res => {
+ this.hasDocuwareFile = res.data;
+ });
+ }
+
+ uploadDocuware(force) {
+ if (!force)
+ return this.$.pdfToTablet.show();
+
+ return this.$http.post(`Docuwares/${this.id}/upload`, {fileCabinet: 'deliveryNote'})
+ .then(() => {
+ this.vnApp.showSuccess(this.$t('PDF sent!'));
+ this.$.balanceCreate.show();
+ });
+ }
}
Controller.$inject = ['$element', '$scope', 'vnReport', 'vnEmail'];
diff --git a/modules/ticket/front/descriptor-menu/index.spec.js b/modules/ticket/front/descriptor-menu/index.spec.js
index 48b64f4a0..67dc0affa 100644
--- a/modules/ticket/front/descriptor-menu/index.spec.js
+++ b/modules/ticket/front/descriptor-menu/index.spec.js
@@ -286,9 +286,34 @@ describe('Ticket Component vnTicketDescriptorMenu', () => {
describe('hasDocuware()', () => {
it('should call hasDocuware method', () => {
- $httpBackend.whenPOST(`Docuwares/${ticket.id}/checkFile`).respond();
+ $httpBackend.whenPOST(`Docuwares/${ticket.id}/checkFile`).respond(true);
controller.hasDocuware();
$httpBackend.flush();
+
+ expect(controller.hasDocuwareFile).toBe(true);
+ });
+ });
+
+ describe('uploadDocuware()', () => {
+ it('should open dialog if not force', () => {
+ controller.$.pdfToTablet = {show: () => {}};
+ jest.spyOn(controller.$.pdfToTablet, 'show');
+ controller.uploadDocuware(false);
+
+ expect(controller.$.pdfToTablet.show).toHaveBeenCalled();
+ });
+
+ it('should make a query and show balance create', () => {
+ controller.$.balanceCreate = {show: () => {}};
+ jest.spyOn(controller.$.balanceCreate, 'show');
+ jest.spyOn(controller.vnApp, 'showSuccess');
+
+ $httpBackend.whenPOST(`Docuwares/${ticket.id}/upload`).respond(true);
+ controller.uploadDocuware(true);
+ $httpBackend.flush();
+
+ expect(controller.vnApp.showSuccess).toHaveBeenCalled();
+ expect(controller.$.balanceCreate.show).toHaveBeenCalled();
});
});
diff --git a/modules/ticket/front/descriptor-menu/locale/es.yml b/modules/ticket/front/descriptor-menu/locale/es.yml
index a2725f485..b51637524 100644
--- a/modules/ticket/front/descriptor-menu/locale/es.yml
+++ b/modules/ticket/front/descriptor-menu/locale/es.yml
@@ -1,9 +1,11 @@
Show Delivery Note...: Ver albarán...
Send Delivery Note...: Enviar albarán...
as PDF: como PDF
+as PDF signed: como PDF firmado
as CSV: como CSV
as PDF without prices: como PDF sin precios
Send PDF: Enviar PDF
+Send PDF to tablet: Enviar PDF a tablet
Send CSV: Enviar CSV
Send CSV Delivery Note: Enviar albarán en CSV
Send PDF Delivery Note: Enviar albarán en PDF
@@ -13,3 +15,6 @@ Invoice sent: Factura enviada
The following refund ticket have been created: "Se ha creado siguiente ticket de abono: {{ticketId}}"
Transfer client: Transferir cliente
SMS Notify changes: SMS Notificar cambios
+PDF sent!: ¡PDF enviado!
+Already exist signed delivery note: Ya existe albarán de entrega firmado
+Are you sure you want to replace this delivery note?: ¿Seguro que quieres reemplazar este albarán de entrega?
diff --git a/package-lock.json b/package-lock.json
index 550a1ec76..31820196f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,7 +9,7 @@
"version": "9.0.0",
"license": "GPL-3.0",
"dependencies": {
- "axios": "^0.25.0",
+ "axios": "^1.2.2",
"bcrypt": "^5.0.1",
"bmp-js": "^0.1.0",
"compression": "^1.7.3",
@@ -3893,10 +3893,13 @@
"license": "MIT"
},
"node_modules/axios": {
- "version": "0.25.0",
- "license": "MIT",
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.2.tgz",
+ "integrity": "sha512-bz/J4gS2S3I7mpN/YZfGFTqhXTYzRho8Ay38w2otuuDR322KzFIWm/4W2K6gIwvWaws5n+mnb7D1lN9uD+QH6Q==",
"dependencies": {
- "follow-redirects": "^1.14.7"
+ "follow-redirects": "^1.15.0",
+ "form-data": "^4.0.0",
+ "proxy-from-env": "^1.1.0"
}
},
"node_modules/babel-jest": {
@@ -8401,14 +8404,15 @@
}
},
"node_modules/follow-redirects": {
- "version": "1.14.9",
+ "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"
},
@@ -28842,9 +28846,13 @@
"version": "1.11.0"
},
"axios": {
- "version": "0.25.0",
+ "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.14.7"
+ "follow-redirects": "^1.15.0",
+ "form-data": "^4.0.0",
+ "proxy-from-env": "^1.1.0"
}
},
"babel-jest": {
@@ -31964,7 +31972,9 @@
}
},
"follow-redirects": {
- "version": "1.14.9"
+ "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",
diff --git a/package.json b/package.json
index 8cc33526d..9633751a0 100644
--- a/package.json
+++ b/package.json
@@ -12,7 +12,7 @@
"node": ">=14"
},
"dependencies": {
- "axios": "^0.25.0",
+ "axios": "^1.2.2",
"bcrypt": "^5.0.1",
"bmp-js": "^0.1.0",
"compression": "^1.7.3",