feat(docuware): upload and send pdf
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Alex Moreno 2023-01-09 15:11:53 +01:00
parent 46f36e1de1
commit 382aad2622
11 changed files with 629 additions and 83 deletions

View File

@ -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
### Changed

Binary file not shown.

View File

@ -85,6 +85,12 @@ module.exports = Self => {
`${docuwareUrl}/FileCabinets/${fileCabinetId}/Query/DialogExpression?dialogId=${dialogId}`, options);
JSON.parse(response.body).Items[0].Id;
// const file = JSON.parse(response.body).Items[0];
// const state = file.Fields.find(field => field.FieldName == 'ESTADO');
// if (state != 'Firmado')
// return false;
return true;
} catch (error) {
return false;

View File

@ -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, 'deliveryClient', 'findTicket');
return email.send({
overrideAttachments: true,
attachments: [{
filename: `${id}.pdf`,
content: docuwareFile[0]
}]
});
};
};

View File

@ -1,9 +1,6 @@
/* eslint max-len: ["error", { "code": 180 }]*/
const got = require('got');
const axios = require('axios');
const UserError = require('vn-loopback/util/user-error');
const FormData = require('form-data');
const fs = require('fs-extra');
module.exports = Self => {
Self.remoteMethodCtx('download', {
@ -13,19 +10,19 @@ module.exports = Self => {
{
arg: 'id',
type: 'number',
description: 'The id',
description: 'The ticket id',
http: {source: 'path'}
},
{
arg: 'fileCabinet',
type: 'string',
description: 'The id',
description: 'The file cabinet',
http: {source: 'path'}
},
{
arg: 'dialog',
type: 'string',
description: 'The id',
description: 'The dialog',
http: {source: 'path'}
}
],
@ -92,7 +89,6 @@ module.exports = Self => {
// get dialog
const dialogResponse = await got.get(`${docuwareUrl}/FileCabinets/${fileCabinetId}/dialogs`, options);
console.log(`${docuwareUrl}/FileCabinets/${fileCabinetId}/dialogs`);
const dialogJson = JSON.parse(dialogResponse.body).Dialog;
const dialogId = dialogJson.find(dialogs => dialogs.DisplayName === 'find').Id;
@ -111,48 +107,9 @@ module.exports = Self => {
}
};
// const stream = got.stream(downloadUri, downloadOptions);
const stream = got.stream(downloadUri, downloadOptions);
const uploadUri = `${docuwareUrl}/FileCabinets/${fileCabinetId}/Documents?storeDialogId=1f665772-c936-4e13-aa2a-f209b1a7070e`;
const form = new FormData();
const file = await fs.readFile('back/methods/docuware/10.pdf');
form.append('file', file, '10.pdf');
const uploadOptions = {
'headers': {
'Cookie': cookie,
}
};
const fileData = {
formData: {
'document': {
value: JSON.stringify({Fields: {}}),
options: {
filename: 'document.json',
contentType: 'application/json',
},
},
'file[]': {
value: fs.createReadStream('back/methods/docuware/10.pdf'),
options: {
filename: '10.pdf',
contentType: null
}
}
}
};
Object.assign(uploadOptions, fileData);
try {
const upload = await axios.post(uploadUri, file, uploadOptions);
console.log('UPLOAD FINISHED');
} catch (e) {
console.log('ERROR CATCHED:', e);
console.log('ERROR CATCHED');
return;
}
// return [stream, contentType, fileName];
return;
return [stream, contentType, fileName];
} catch (error) {
if (error.code === 'ENOENT')
throw new UserError('The DOCUWARE PDF document does not exists');

View File

@ -0,0 +1,470 @@
const got = require('got');
const UserError = require('vn-loopback/util/user-error');
const request = require('request');
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: [
{
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/upload`,
verb: 'POST'
}
});
Self.upload = async function(ctx, id, fileCabinet, dialog) {
const myUserId = ctx.req.accessToken.userId;
if (!myUserId)
throw new UserError(`You don't have enough privileges`);
const models = Self.app.models;
const docuwareConfig = await models.DocuwareConfig.findOne();
const docuwareInfo = await models.Docuware.findOne({
where: {
code: fileCabinet,
dialogName: dialog
}
});
const docuwareUrl = docuwareConfig.url;
const cookie = docuwareConfig.token;
const fileCabinetName = docuwareInfo.fileCabinetName;
const options = {
'headers': {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Cookie': cookie
}
};
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;
// get dialog
const dialogResponse = await got.get(`${docuwareUrl}/FileCabinets/${fileCabinetId}/dialogs`, options);
const dialogJson = JSON.parse(dialogResponse.body).Dialog;
const storeDialogId = dialogJson.find(dialogs => dialogs.DisplayName === 'Archivar').Id;
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']
}
}]
});
const [taxes] = await models.Ticket.rawSql('CALL vn.ticketGetTaxAdd(?)', [id]);
// upload file
const templateJson = {
'Fields': [
{
'FieldName': 'N__ALBAR_N',
'ReadOnly': false,
'SystemField': false,
'ItemElementName': 'string',
'PointAndShootInfo': {
'Box': [
{
'Left': 2531,
'Top': 3645,
'Width': 257,
'Height': 230,
'PageNumber': 0
}
],
'PageNumber': 0
},
'IsAutoNumber': false,
'IsNull': false,
'Item': id,
'FieldValue': id
},
{
'FieldName': 'CIF_PROVEEDOR',
'ReadOnly': false,
'SystemField': false,
'ItemElementName': 'string',
'PointAndShootInfo': {
'Box': [
{
'Left': 6176,
'Top': 4624,
'Width': 839,
'Height': 168,
'PageNumber': 0
}
],
'PageNumber': 0
},
'IsAutoNumber': false,
'IsNull': false,
'Item': ticket.client().fi,
'FieldValue': ticket.client().fi
},
{
'FieldName': 'CODIGO_PROVEEDOR',
'ReadOnly': false,
'SystemField': false,
'ItemElementName': 'string',
'PointAndShootInfo': {
'Box': [
{
'Left': 2531,
'Top': 3240,
'Width': 514,
'Height': 230,
'PageNumber': 0
}
],
'PageNumber': 0
},
'IsAutoNumber': false,
'IsNull': false,
'Item': ticket.client().id,
'FieldValue': ticket.client().id
},
{
'FieldName': 'NOMBRE_PROVEEDOR',
'ReadOnly': false,
'SystemField': false,
'ItemElementName': 'string',
'PointAndShootInfo': {
'Box': [
{
'Left': 6175,
'Top': 4264,
'Width': 858,
'Height': 168,
'PageNumber': 0
}
],
'PageNumber': 0
},
'IsAutoNumber': false,
'IsNull': false,
'Item': ticket.client().socialName,
'FieldValue': ticket.client().socialName
},
{
'FieldName': 'FECHA_FACTURA',
'ReadOnly': false,
'SystemField': false,
'ItemElementName': 'date',
'PointAndShootInfo': {
'Box': [
{
'Left': 2531,
'Top': 4050,
'Width': 1181,
'Height': 230,
'PageNumber': 0
}
],
'PageNumber': 0
},
'IsAutoNumber': false,
'IsNull': false,
'Item': ticket.shipped,
'FieldValue': ticket.shipped
},
{
'FieldName': 'TIPO_IVA__1_',
'ReadOnly': false,
'SystemField': false,
'ItemElementName': 'Decimal',
'PointAndShootInfo': {
'Box': [
{
'Left': 9537,
'Top': 10057,
'Width': 615,
'Height': 168,
'PageNumber': 0
}
],
'PageNumber': 0
},
'IsAutoNumber': false,
'IsNull': false,
'Item': taxes[0].rate,
'FieldValue': taxes[0].rate
},
{
'FieldName': 'BASE_IMPONIBLE__1_',
'ReadOnly': false,
'SystemField': false,
'ItemElementName': 'Decimal',
'PointAndShootInfo': {
'Box': [
{
'Left': 8907,
'Top': 10567,
'Width': 419,
'Height': 168,
'PageNumber': 0
}
],
'PageNumber': 0
},
'IsAutoNumber': false,
'IsNull': false,
'Item': ticket.totalWithoutVat,
'FieldValue': ticket.totalWithoutVat
},
{
'FieldName': 'IMPORTE_IVA__1_',
'ReadOnly': false,
'SystemField': false,
'ItemElementName': 'Decimal',
'PointAndShootInfo': {
'Box': [
{
'Left': 10423,
'Top': 10057,
'Width': 419,
'Height': 168,
'PageNumber': 0
}
],
'PageNumber': 0
},
'IsAutoNumber': false,
'IsNull': false,
'Item': taxes[0].tax,
'FieldValue': taxes[0].tax
},
{
'FieldName': 'TIPO_IVA__2_',
'ReadOnly': false,
'SystemField': false,
'ItemElementName': 'Decimal',
'PointAndShootInfo': null,
'IsAutoNumber': false,
'IsNull': true,
'Item': null,
'FieldValue': null
},
{
'FieldName': 'BASE_IMPONIBLE__2_',
'ReadOnly': false,
'SystemField': false,
'ItemElementName': 'Decimal',
'PointAndShootInfo': null,
'IsAutoNumber': false,
'IsNull': true,
'Item': null,
'FieldValue': null
},
{
'FieldName': 'IMPORTE_IVA__2_',
'ReadOnly': false,
'SystemField': false,
'ItemElementName': 'Decimal',
'PointAndShootInfo': null,
'IsAutoNumber': false,
'IsNull': true,
'Item': null,
'FieldValue': null
},
{
'FieldName': 'TIPO_IVA__3_',
'ReadOnly': false,
'SystemField': false,
'ItemElementName': 'Decimal',
'PointAndShootInfo': null,
'IsAutoNumber': false,
'IsNull': true,
'Item': null,
'FieldValue': null
},
{
'FieldName': 'BASE_IMPONIBLE__3_',
'ReadOnly': false,
'SystemField': false,
'ItemElementName': 'Decimal',
'PointAndShootInfo': null,
'IsAutoNumber': false,
'IsNull': true,
'Item': null,
'FieldValue': null
},
{
'FieldName': 'IMPORTE_IVA__3_',
'ReadOnly': false,
'SystemField': false,
'ItemElementName': 'Decimal',
'PointAndShootInfo': null,
'IsAutoNumber': false,
'IsNull': true,
'Item': null,
'FieldValue': null
},
{
'FieldName': 'IRPF',
'ReadOnly': false,
'SystemField': false,
'ItemElementName': 'Decimal',
'PointAndShootInfo': null,
'IsAutoNumber': false,
'IsNull': true,
'Item': null,
'FieldValue': null
},
{
'FieldName': 'TOTAL_FACTURA',
'ReadOnly': false,
'SystemField': false,
'ItemElementName': 'Decimal',
'PointAndShootInfo': {
'Box': [
{
'Left': 10423,
'Top': 10958,
'Width': 419,
'Height': 168,
'PageNumber': 0
}
],
'PageNumber': 0
},
'IsAutoNumber': false,
'IsNull': false,
'Item': ticket.totalWithVat,
'FieldValue': ticket.totalWithVat
},
{
'FieldName': 'ESTADO',
'ReadOnly': false,
'SystemField': false,
'ItemElementName': 'string',
'PointAndShootInfo': null,
'IsAutoNumber': false,
'IsNull': false,
'Item': 'Pendiente procesar',
'FieldValue': 'Pendiente procesar'
},
{
'FieldName': 'URL',
'ReadOnly': false,
'SystemField': false,
'ItemElementName': 'string',
'PointAndShootInfo': null,
'IsAutoNumber': false,
'IsNull': true,
'Item': null,
'FieldValue': ''
},
{
'FieldName': 'FIRMA_',
'ReadOnly': false,
'SystemField': false,
'ItemElementName': 'string',
'PointAndShootInfo': null,
'IsAutoNumber': false,
'IsNull': false,
'Item': 'Si',
'FieldValue': 'Si'
},
{
'FieldName': 'FILTRO_TABLET',
'ReadOnly': false,
'SystemField': false,
'ItemElementName': 'string',
'PointAndShootInfo': null,
'IsAutoNumber': false,
'IsNull': false,
'Item': 'Tablet1',
'FieldValue': 'Tablet1'
}
]
};
const uploadUri = `${docuwareUrl}/FileCabinets/${fileCabinetId}/Documents?StoreDialogId=${storeDialogId}`;
const optionsUpload = {
'method': 'POST',
'url': uploadUri,
'headers': {
'Content-Type': 'multipart/form-data',
'X-File-ModifiedDate': new Date(),
'Cookie': cookie
},
'formData': {
'document': {
'value': JSON.stringify(templateJson),
'options': {
'filename': 'store.json',
'contentType': null
}
},
'file[]': {
'value': deliveryNote[0],
'options': {
'filename': 'deliveryNote.pdf',
'contentType': deliveryNote[1]
}
}
}
};
try {
return new Promise((resolve, reject) => {
request.post(optionsUpload, function(error) {
if (error) return reject(error);
resolve();
});
});
} catch (error) {
console.log(error);
return;
}
} catch (error) {
if (error.code === 'ENOENT')
throw new UserError('The DOCUWARE PDF document does not exists');
throw error;
}
};
};

View File

@ -1,4 +1,6 @@
module.exports = Self => {
require('../methods/docuware/download')(Self);
require('../methods/docuware/upload')(Self);
require('../methods/docuware/checkFile')(Self);
require('../methods/docuware/deliveryNoteEmail')(Self);
};

View File

@ -25,14 +25,5 @@
"find": {
"type": "string"
}
},
"acls": [
{
"property": "*",
"accessType": "*",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}
]
}
}
}

View File

@ -0,0 +1,10 @@
INSERT INTO `vn`.`docuware` (`code`, `fileCabinetName`, `dialogName`, `find`)
VALUES
('deliveryClient', 'Albaranes cliente', 'storeTicket', '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');

View File

@ -21,26 +21,17 @@
Add turn
</vn-item>
<vn-item class="dropdown"
vn-click-stop="showDeliveryNoteMenu.show($event, 'left'); $ctrl.hasDocuware()"
vn-click-stop="showDeliveryNoteMenu.show($event, 'left')"
translate>
Show Delivery Note...
<vn-menu vn-id="showDeliveryNoteMenu">
<vn-list>
<vn-item
ng-if="!$ctrl.hasDocuwareFile"
ng-click="$ctrl.showPdfDeliveryNote('deliveryNote')"
translate>
as PDF
</vn-item>
<a class="vn-item"
ng-if="$ctrl.hasDocuwareFile"
href='api/Docuwares/{{$ctrl.ticket.id}}/download/deliveryClient/findTicket?access_token={{$ctrl.vnToken.token}}'
target="_blank"
translate>
as PDF Docuware
</a>
<vn-item
ng-if="!$ctrl.hasDocuwareFile"
ng-click="$ctrl.showPdfDeliveryNote('withoutPrices')"
translate>
as PDF without prices
@ -64,11 +55,6 @@
translate>
Send PDF
</vn-item>
<vn-item
ng-click="sendPdfConfirmation.show({email: $ctrl.ticket.client.email})"
translate>
Send PDF Docuware
</vn-item>
<vn-item
ng-click="sendCsvConfirmation.show({email: $ctrl.ticket.client.email})"
translate>
@ -77,6 +63,40 @@
</vn-list>
</vn-menu>
</vn-item>
<vn-item class="dropdown"
vn-click-stop="showDeliveryNoteMenu.show($event, 'left'); $ctrl.hasDocuware()"
translate>
Docuware options...
<vn-menu vn-id="showDeliveryNoteMenu">
<vn-list ng-if="$ctrl.isLoadingDocuware">
<div class="spinner-wrapper">
<vn-spinner enable="$ctrl.isLoadingDocuware"></vn-spinner>
Loading Docuware info
</div>
</vn-list>
<vn-list ng-if="!$ctrl.isLoadingDocuware">
<a class="vn-item"
ng-if="$ctrl.hasDocuwareFile"
href='api/Docuwares/{{$ctrl.ticket.id}}/download/deliveryClient/findTicket?access_token={{$ctrl.vnToken.token}}'
target="_blank"
translate>
Show PDF
</a>
<vn-item
ng-if="!$ctrl.hasDocuwareFile"
ng-click="$ctrl.uploadDocuware()"
translate>
Upload Salix PDF
</vn-item>
<vn-item
ng-if="$ctrl.hasDocuwareFile"
ng-click="$ctrl.sendDocuwarePdfDeliveryNote({email: $ctrl.ticket.client.email})"
translate>
Send PDF
</vn-item>
</vn-list>
</vn-menu>
</vn-item>
<vn-item
ng-click="$ctrl.showPdfDeliveryNote('proforma')"
translate>

View File

@ -133,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,
@ -311,6 +302,31 @@ class Controller extends Section {
return this.$http.post(`Tickets/${this.id}/sendSms`, sms)
.then(() => this.vnApp.showSuccess(this.$t('SMS sent')));
}
hasDocuware() {
const params = {
fileCabinet: 'deliveryClient',
dialog: 'findTicket'
};
this.isLoadingDocuware = true;
this.$http.post(`Docuwares/${this.id}/checkFile`, params)
.then(res => {
this.hasDocuwareFile = res.data;
this.isLoadingDocuware = false;
});
}
uploadDocuware() {
return this.$http.post(`Docuwares/${this.id}/upload`, {fileCabinet: 'deliveryClient', dialog: 'storeTicket'})
.then(() => this.vnApp.showSuccess(this.$t('PDF uploaded!')));
}
sendDocuwarePdfDeliveryNote($data) {
return this.vnEmail.send(`Docuwares/${this.id}/delivery-note-email`, {
recipientId: this.ticket.client.id,
recipient: $data.email
});
}
}
Controller.$inject = ['$element', '$scope', 'vnReport', 'vnEmail'];