diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3f241b91f..64ddda720 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..fe256e2ea 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,6 @@
"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"
+ "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/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",