feat(ticket_descriptor-menu): docuware implemented
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Alex Moreno 2022-02-21 08:48:53 +01:00
parent 06255e0a07
commit 0f4649c50f
14 changed files with 312 additions and 398 deletions

View File

@ -1,16 +1,27 @@
const got = require('got'); const got = require('got');
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => { module.exports = Self => {
Self.remoteMethodCtx('checkFile', { Self.remoteMethodCtx('checkFile', {
description: 'Download an docuware PDF', description: 'Check if exist docuware file',
accessType: 'READ', accessType: 'READ',
accepts: [ accepts: [
{ {
arg: 'id', arg: 'id',
type: 'String', type: 'number',
description: 'The invoice id', description: 'The id',
http: {source: 'path'} http: {source: 'path'}
},
{
arg: 'fileCabinet',
type: 'string',
required: true,
description: 'The fileCabinet name'
},
{
arg: 'dialog',
type: 'string',
required: true,
description: 'The dialog name'
} }
], ],
returns: { returns: {
@ -19,21 +30,21 @@ module.exports = Self => {
}, },
http: { http: {
path: `/:id/checkFile`, path: `/:id/checkFile`,
verb: 'GET' verb: 'POST'
} }
}); });
Self.checkFile = async function(ctx, id) { Self.checkFile = async function(ctx, id, fileCabinet, dialog) {
// const fileCabinet = 'ad2c49df-8976-4941-bb19-9b30685f14a4'; const myUserId = ctx.req.accessToken.userId;
// hay que crear tambien una busqueda por cada fileCabinet if (!myUserId)
// columnas necesarias. seccion, fileCabinet, DBName, dialog return false;
const models = Self.app.models; const models = Self.app.models;
const docuwareConfig = await models.DocuwareConfig.findOne(); const docuwareConfig = await models.DocuwareConfig.findOne();
const docuwareInfo = await models.Docuware.findOne({ const docuwareInfo = await models.Docuware.findOne({
where: { where: {
name: 'deliveryClient', name: fileCabinet,
dialogName: 'findTicket' dialogName: dialog
} }
}); });
@ -41,7 +52,6 @@ module.exports = Self => {
const cookie = docuwareConfig.token; const cookie = docuwareConfig.token;
const fileCabinetName = docuwareInfo.fileCabinetName; const fileCabinetName = docuwareInfo.fileCabinetName;
const find = docuwareInfo.find; const find = docuwareInfo.find;
const options = { const options = {
'headers': { 'headers': {
'Accept': 'application/json', 'Accept': 'application/json',
@ -49,29 +59,32 @@ module.exports = Self => {
'Cookie': cookie 'Cookie': cookie
} }
}; };
// get fileCabinetId const condtions = {
const fileCabinetResponse = await got.get(`${docuwareUrl}/FileCabinets`, options).json(); condition: [
const fileCabinetId = fileCabinetResponse.FileCabinet.find(dialogs => dialogs.Name === fileCabinetName).Id; {
DBName: find,
// get dialog Value: [id]
const dialogResponse = await got.get(`${docuwareUrl}/FileCabinets/${fileCabinetId}/dialogs`, options).json(); }
const dialogId = dialogResponse.Dialog.find(dialogs => dialogs.DisplayName === 'find').Id; ]
// get docuwareID
const docuwareOptions = {
'headers': {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Cookie': cookie
},
'body': JSON.stringify({'Condition': [{DBName: find, Value: [id]}]})
}; };
const response = await got.post(
`${docuwareUrl}/FileCabinets/${fileCabinetId}/Query/DialogExpression?dialogId=${dialogId}`,
docuwareOptions
);
try { 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 dialogId = dialogJson.find(dialogs => dialogs.DisplayName === 'find').Id;
// get docuwareID
Object.assign(options, {'body': JSON.stringify(condtions)});
const response = await got.post(
`${docuwareUrl}/FileCabinets/${fileCabinetId}/Query/DialogExpression?dialogId=${dialogId}`, options);
JSON.parse(response.body).Items[0].Id; JSON.parse(response.body).Items[0].Id;
return true; return true;
} catch (error) { } catch (error) {
return false; return false;

View File

@ -1,9 +1,6 @@
/* eslint max-len: ["error", { "code": 180 }]*/
const got = require('got'); const got = require('got');
const fs = require('fs-extra');
const path = require('path');
const UserError = require('vn-loopback/util/user-error'); const UserError = require('vn-loopback/util/user-error');
const {promisify} = require('util');
const nodeStream = require('stream');
module.exports = Self => { module.exports = Self => {
Self.remoteMethodCtx('download', { Self.remoteMethodCtx('download', {
@ -13,7 +10,19 @@ module.exports = Self => {
{ {
arg: 'id', arg: 'id',
type: 'number', type: 'number',
description: 'The ticket id', description: 'The id',
http: {source: 'path'}
},
{
arg: 'fileCabinet',
type: 'string',
description: 'The id',
http: {source: 'path'}
},
{
arg: 'dialog',
type: 'string',
description: 'The id',
http: {source: 'path'} http: {source: 'path'}
} }
], ],
@ -24,34 +33,31 @@ module.exports = Self => {
root: true root: true
}, { }, {
arg: 'Content-Type', arg: 'Content-Type',
type: 'String', type: 'string',
http: {target: 'header'} http: {target: 'header'}
}, { }, {
arg: 'Content-Disposition', arg: 'Content-Disposition',
type: 'String', type: 'string',
http: {target: 'header'} http: {target: 'header'}
} }
], ],
http: { http: {
path: `/:id/download`, path: `/:id/download/:fileCabinet/:dialog`,
verb: 'GET' verb: 'GET'
} }
}); });
Self.download = async function(ctx, id) { Self.download = async function(ctx, id, fileCabinet, dialog) {
// const fileCabinet = 'ad2c49df-8976-4941-bb19-9b30685f14a4'; const myUserId = ctx.req.accessToken.userId;
// hay que crear tambien una busqueda por cada fileCabinet
// columnas necesarias. seccion, fileCabinet, DBName, dialog
/* const myUserId = ctx.req.accessToken.userId;
if (!myUserId) if (!myUserId)
throw new UserError(`You don't have enough privileges`);*/ throw new UserError(`You don't have enough privileges`);
const models = Self.app.models; const models = Self.app.models;
const docuwareConfig = await models.DocuwareConfig.findOne(); const docuwareConfig = await models.DocuwareConfig.findOne();
const docuwareInfo = await models.Docuware.findOne({ const docuwareInfo = await models.Docuware.findOne({
where: { where: {
name: 'deliveryClient', name: fileCabinet,
dialogName: 'findTicket' dialogName: dialog
} }
}); });
@ -59,7 +65,6 @@ module.exports = Self => {
const cookie = docuwareConfig.token; const cookie = docuwareConfig.token;
const fileCabinetName = docuwareInfo.fileCabinetName; const fileCabinetName = docuwareInfo.fileCabinetName;
const find = docuwareInfo.find; const find = docuwareInfo.find;
const options = { const options = {
'headers': { 'headers': {
'Accept': 'application/json', 'Accept': 'application/json',
@ -67,71 +72,44 @@ module.exports = Self => {
'Cookie': cookie 'Cookie': cookie
} }
}; };
// get fileCabinetId const condtions = {
const fileCabinetResponse = await got.get(`${docuwareUrl}/FileCabinets`, options).json(); condition: [
const fileCabinetId = fileCabinetResponse.FileCabinet.find(dialogs => dialogs.Name === fileCabinetName).Id; {
DBName: find,
// get dialog Value: [id]
const dialogResponse = await got.get(`${docuwareUrl}/FileCabinets/${fileCabinetId}/dialogs`, options).json(); }
const dialogId = dialogResponse.Dialog.find(dialogs => dialogs.DisplayName === 'find').Id; ]
// get docuwareID
const docuwareOptions = {
'headers': {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Cookie': cookie
},
'body': JSON.stringify({'Condition': [{DBName: find, Value: [0]}]})
};
const response = await got.post(
`${docuwareUrl}/FileCabinets/${fileCabinetId}/Query/DialogExpression?dialogId=${dialogId}`,
docuwareOptions
);
const docuwareId = JSON.parse(response.body).Items[0].Id;
// download file
const downloadUrl = `${docuwareUrl}/FileCabinets/${fileCabinetId}/Documents/${docuwareId}/FileDownload?targetFileType=Auto&keepAnnotations=false`;
const downloadOptions = {
'headers': {
'Cookie': cookie
}
}; };
try { try {
// save file // get fileCabinetId
const ticket = await models.Ticket.findById(id); 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 shipped = ticket.shipped; // get dialog
const year = shipped.getFullYear().toString(); const dialogResponse = await got.get(`${docuwareUrl}/FileCabinets/${fileCabinetId}/dialogs`, options);
const month = (shipped.getMonth() + 1).toString(); const dialogJson = JSON.parse(dialogResponse.body).Dialog;
const day = shipped.getDate().toString(); const dialogId = dialogJson.find(dialogs => dialogs.DisplayName === 'find').Id;
const fileName = `${year}${id}.pdf`;
const container = await models.DocuwareContainer.container(year); // get docuwareID
const rootPath = container.client.root; Object.assign(options, {'body': JSON.stringify(condtions)});
const src = path.join(rootPath, year, month, day); const response = await got.post(`${docuwareUrl}/FileCabinets/${fileCabinetId}/Query/DialogExpression?dialogId=${dialogId}`, options);
const fileSrc = path.join(src, fileName); const docuwareId = JSON.parse(response.body).Items[0].Id;
await fs.mkdir(src, {recursive: true}); // download & save file
const fileName = `filename="${id}.pdf"`;
const pipeline = promisify(nodeStream.pipeline); const contentType = 'application/pdf';
await pipeline( const downloadUri = `${docuwareUrl}/FileCabinets/${fileCabinetId}/Documents/${docuwareId}/FileDownload?targetFileType=Auto&keepAnnotations=false`;
got.stream(downloadUrl, downloadOptions), const downloadOptions = {
fs.createWriteStream(fileSrc) 'headers': {
); 'Cookie': cookie
}
// open file
const file = {
path: fileSrc,
contentType: 'application/pdf',
name: fileName
}; };
await fs.access(file.path); const stream = got.stream(downloadUri, downloadOptions);
let stream = fs.createReadStream(file.path);
return [stream, file.contentType, `filename="${file.name}"`]; return [stream, contentType, fileName];
} catch (error) { } catch (error) {
if (error.code === 'ENOENT') if (error.code === 'ENOENT')
throw new UserError('The DOCUWARE PDF document does not exists'); throw new UserError('The DOCUWARE PDF document does not exists');

View File

@ -1,129 +1,64 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
const got = require('got');
describe('image upload()', () => { describe('docuware download()', () => {
describe('as buyer', () => { const ticketId = 1;
const buyerId = 35; const userId = 9;
const workerId = 1106; const ctx = {
const itemId = 4; req: {
it('should try to upload a file for the collection "catalog" and throw a privileges error', async() => { accessToken: {userId: userId},
const ctx = {req: {accessToken: {userId: buyerId}}, headers: {origin: 'http://localhost:5000'},
args: { }
id: workerId, };
collection: 'user'
}
};
let error; const fileCabinetName = 'deliveryClientTest';
try { const dialogDisplayName = 'find';
await app.models.Image.upload(ctx); const dialogName = 'findTest';
} catch (err) {
error = err;
}
expect(error.message).toEqual(`You don't have enough privileges`); const gotGetResponse = {
}); body: JSON.stringify(
{
FileCabinet: [
{Id: 12, Name: fileCabinetName}
],
Dialog: [
{Id: 34, DisplayName: dialogDisplayName}
]
})
};
it('should call to the TempContainer upload method for the collection "catalog"', async() => { it('should return exist file in docuware', async() => {
const containerModel = app.models.TempContainer; const gotPostResponse = {
spyOn(containerModel, 'upload'); body: JSON.stringify(
{
Items: [
{Id: 56}
],
})
};
const ctx = {req: {accessToken: {userId: buyerId}}, spyOn(got, 'get').and.returnValue(new Promise(resolve => resolve(gotGetResponse)));
args: { spyOn(got, 'post').and.returnValue(new Promise(resolve => resolve(gotPostResponse)));
id: itemId,
collection: 'catalog'
}
};
try { const result = await models.Docuware.checkFile(ctx, ticketId, fileCabinetName, dialogName);
await app.models.Image.upload(ctx);
} catch (err) { }
expect(containerModel.upload).toHaveBeenCalled(); expect(result).toEqual(true);
});
}); });
describe('as marketing', () => { it('should return not exist file in docuware', async() => {
const marketingId = 51; const gotPostResponse = {
const workerId = 1106; body: JSON.stringify(
const itemId = 4; {
Items: [],
})
};
it('should be able to call to the TempContainer upload method for the collection "user"', async() => { spyOn(got, 'get').and.returnValue(new Promise(resolve => resolve(gotGetResponse)));
const containerModel = app.models.TempContainer; spyOn(got, 'post').and.returnValue(new Promise(resolve => resolve(gotPostResponse)));
spyOn(containerModel, 'upload');
const ctx = {req: {accessToken: {userId: marketingId}}, const result = await models.Docuware.checkFile(ctx, ticketId, fileCabinetName, dialogName);
args: {
id: workerId,
collection: 'user'
}
};
try { expect(result).toEqual(false);
await app.models.Image.upload(ctx);
} catch (err) { }
expect(containerModel.upload).toHaveBeenCalled();
});
it('should be able to call to the TempContainer upload method for the collection "catalog"', async() => {
const containerModel = app.models.TempContainer;
spyOn(containerModel, 'upload');
const ctx = {req: {accessToken: {userId: marketingId}},
args: {
id: itemId,
collection: 'catalog'
}
};
try {
await app.models.Image.upload(ctx);
} catch (err) { }
expect(containerModel.upload).toHaveBeenCalled();
});
});
describe('as hhrr', () => {
const hhrrId = 37;
const workerId = 1106;
const itemId = 4;
it('should upload a file for the collection "user" and call to the TempContainer upload method', async() => {
const containerModel = app.models.TempContainer;
spyOn(containerModel, 'upload');
const ctx = {req: {accessToken: {userId: hhrrId}},
args: {
id: itemId,
collection: 'user'
}
};
try {
await app.models.Image.upload(ctx);
} catch (err) { }
expect(containerModel.upload).toHaveBeenCalled();
});
it('should try to upload a file for the collection "catalog" and throw a privilege error', async() => {
const ctx = {req: {accessToken: {userId: hhrrId}},
args: {
id: workerId,
collection: 'catalog'
}
};
let error;
try {
await app.models.Image.upload(ctx);
} catch (err) {
error = err;
}
expect(error.message).toEqual(`You don't have enough privileges`);
});
}); });
}); });

View File

@ -1,9 +1,10 @@
const models = require('vn-loopback/server/server').models; const models = require('vn-loopback/server/server').models;
const fs = require('fs-extra'); const got = require('got');
const stream = require('stream');
describe('image download()', () => { describe('docuware download()', () => {
const userId = 9; const userId = 9;
const invoiceId = 1; const ticketId = 1;
const ctx = { const ctx = {
req: { req: {
@ -13,16 +14,37 @@ describe('image download()', () => {
}; };
it('should return the downloaded file name', async() => { it('should return the downloaded file name', async() => {
spyOn(models.DocuwareContainer, 'container').and.returnValue({ const fileCabinetName = 'deliveryClientTest';
client: {root: '/path'} const dialogDisplayName = 'find';
}); const dialogName = 'findTest';
spyOn(fs, 'createReadStream').and.returnValue(new Promise(resolve => resolve('streamObject'))); const gotGetResponse = {
spyOn(fs, 'access').and.returnValue(true); body: JSON.stringify(
spyOn(models.InvoiceOut, 'createPdf').and.returnValue(new Promise(resolve => resolve(true))); {
FileCabinet: [
{Id: 12, Name: fileCabinetName}
],
Dialog: [
{Id: 34, DisplayName: dialogDisplayName}
]
})
};
const result = await models.InvoiceOut.download(ctx, invoiceId); 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)));
spyOn(got, 'stream').and.returnValue(new stream.PassThrough({objectMode: true}));
const result = await models.Docuware.download(ctx, ticketId, fileCabinetName, dialogName);
expect(result[1]).toEqual('application/pdf'); expect(result[1]).toEqual('application/pdf');
expect(result[2]).toMatch(/filename="\d{4}T1111111.pdf"/); expect(result[2]).toEqual(`filename="${ticketId}.pdf"`);
}); });
}); });

View File

@ -50,9 +50,6 @@
"DocuwareConfig": { "DocuwareConfig": {
"dataSource": "vn" "dataSource": "vn"
}, },
"DocuwareContainer": {
"dataSource": "docuwareStorage"
},
"EmailUser": { "EmailUser": {
"dataSource": "vn" "dataSource": "vn"
}, },

View File

@ -1,10 +0,0 @@
{
"name": "DocuwareContainer",
"base": "Container",
"acls": [{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}]
}

View File

@ -2444,10 +2444,6 @@ INSERT INTO `bs`.`defaulter` (`clientFk`, `amount`, `created`, `defaulterSinced`
(1107, 500, CURDATE(), CURDATE()), (1107, 500, CURDATE(), CURDATE()),
(1109, 500, CURDATE(), CURDATE()); (1109, 500, CURDATE(), CURDATE());
INSERT INTO `vn`.`docuwareConfig` (`url`, `token`)
VALUES
('https://verdnatura.docuware.cloud/docuware/platform', '.DWPLATFORMAUTH=66C7DCD2B9365EF974AFEB43F61715152082EF39C649CB1506F9ACC34DD54C5B34944DDFBF97EAE5C5147063850B16B3B9FFFB2232FDD03F35B51B1305D5E1E7DB833F6AC560C739E40778932C8BCC64DA7ECE64B0B1F71A3DB986B3710DFA4C061776F9C61DDAA60EF30F7F37FB8733BF4B1830F98102E403E4E751F13F31B582AEDF5B33A25346E10CA34A8559F0CD6ACA39A7379AC67BE061CD27531D02675123FB0D254426E306EC6FA49DED7CF30EBBAD8365BE60D7E919D4AD2EB8F9CD94424DFCD95151C0F6DD3EE8569A7CA4A30D1A3F42DA9DD368A33955A4AFE9CB4FCCC230801BC645AA87A68EC33F6BD165D5A0F02B63D5D832AF936B9398EC428D4ACD41E56848A2CDF797C99226BB2AC48EB5F9C1C5D8C1C7F6A7F67F455ABAC1DBC7443521876B588F369CAE6EC81747BA3134F7EE2662DA296FC2C16528B0AB4839EEE6EE79A82AA3888E4AB53FEC6FFAD26A592ABD76441AFCD634097D0B0B57E16A510D0E6F769710C6F4BDB1476CCDE0967788B90A67BADFB7E37B1F7F60C879A0E9D75AD2BA6647FC11477305B44512AF408845E6099CF64B7A3D77EE; ApplicationGatewayAffinity=c5fad6cb3332163516d49258a1ebf52c; ApplicationGatewayAffinityCORS=c5fad6cb3332163516d49258a1ebf52c; DWPLATFORMBROWSERID=C2173B1A1FE42B449AA12C8465561991BA4664AFA9F44D4C9DD8748FF92EFEBF629E4A75860747C4D8290F70344385CCAFE3EAFD8814CF44F452275C95E89D19D35A178D0BCC6930EF07AC7CF91672F7CB43C2B54CDFAE52BDF17C467FFFE3411FE0D792E4F513726F295648DDE627DF2C6288C89086E2DE6916E4B0A5291AA7C269015A5328147783EC15FB8EF43EE5DAE5A6CD3D318570670234176CAE7B19D9812D3F09D731C5A27A621B39D0564C81774FA993160AAAD833CC75634445B7B47C5A2E26004FF914606B5B0CB897A694F26AD5E80A1EE0D3B7BA4881F8A570');
INSERT INTO `vn`.`docuware` (`name`, `fileCabinetName`, `dialogName` , `find`) INSERT INTO `vn`.`docuware` (`name`, `fileCabinetName`, `dialogName` , `find`)
VALUES VALUES
('deliveryClient', 'Albaranes cliente', 'findTicket', 'N__ALBAR_N'); ('deliveryClientTest', 'deliveryClientTest', 'findTest', 'word');

View File

@ -83,16 +83,5 @@
"application/octet-stream", "application/octet-stream",
"application/pdf" "application/pdf"
] ]
},
"docuwareStorage": {
"name": "docuwareStorage",
"connector": "loopback-component-storage",
"provider": "filesystem",
"root": "./storage/pdfs/docuware",
"maxFileSize": "52428800",
"allowedContentTypes": [
"application/octet-stream",
"application/pdf"
]
} }
} }

View File

@ -1,144 +1,138 @@
<vn-icon-button <vn-icon-button
icon="more_vert" icon="more_vert"
vn-popover="menu"> vn-popover="menu">
</vn-icon-button> </vn-icon-button>
<vn-menu vn-id="menu"> <vn-menu vn-id="menu">
<vn-list> <vn-list>
<vn-item class="dropdown" <vn-item class="dropdown"
vn-click-stop="showInvoiceMenu.show($event, 'left')" vn-click-stop="showInvoiceMenu.show($event, 'left')"
name="showInvoicePdf" name="showInvoicePdf"
translate> translate>
Show invoice... Show invoice...
<vn-menu vn-id="showInvoiceMenu">
<vn-list>
<a class="vn-item"
href="api/InvoiceOuts/{{$ctrl.id}}/download?access_token={{$ctrl.vnToken.token}}"
target="_blank"
name="showInvoicePdf"
translate>
Show as PDF
</a>
<vn-item
ng-click="$ctrl.showCsvInvoice()"
translate>
Show as CSV
</vn-item>
</vn-list>
</vn-menu>
</vn-item>
<vn-item class="dropdown"
vn-click-stop="sendInvoiceMenu.show($event, 'left')"
name="sendInvoice"
translate>
Send invoice...
<vn-menu vn-id="showInvoiceMenu"> <vn-menu vn-id="sendInvoiceMenu">
<vn-list> <vn-list>
<a class="vn-item" <vn-item
href="api/InvoiceOuts/{{$ctrl.id}}/download?access_token={{$ctrl.vnToken.token}}" ng-click="sendPdfConfirmation.show({email: $ctrl.invoiceOut.client.email})"
target="_blank" translate>
name="showInvoicePdf" Send PDF
translate> </vn-item>
Show as PDF <vn-item
</a> ng-click="sendCsvConfirmation.show({email: $ctrl.invoiceOut.client.email})"
<vn-item translate>
ng-click="$ctrl.downloadDocuware()" Send CSV
translate> </vn-item>
Show as DOCUWARE </vn-list>
</vn-item> </vn-menu>
<vn-item </vn-item>
ng-click="$ctrl.showCsvInvoice()" <vn-item
translate> ng-click="deleteConfirmation.show()"
Show as CSV vn-acl="invoicing"
</vn-item> vn-acl-action="remove"
</vn-list> name="deleteInvoice"
</vn-menu> translate>
</vn-item> Delete Invoice
<vn-item class="dropdown" </vn-item>
vn-click-stop="sendInvoiceMenu.show($event, 'left')" <vn-item
name="sendInvoice" ng-click="bookConfirmation.show()"
translate> vn-acl="invoicing"
Send invoice... vn-acl-action="remove"
name="bookInvoice"
<vn-menu vn-id="sendInvoiceMenu"> translate>
<vn-list> Book invoice
<vn-item </vn-item>
ng-click="sendPdfConfirmation.show({email: $ctrl.invoiceOut.client.email})" <vn-item
translate> ng-click="createInvoicePdfConfirmation.show()"
Send PDF ng-show="$ctrl.hasInvoicing || !$ctrl.invoiceOut.hasPdf"
</vn-item> name="regenerateInvoice"
<vn-item translate>
ng-click="sendCsvConfirmation.show({email: $ctrl.invoiceOut.client.email})" {{!$ctrl.invoiceOut.hasPdf ? 'Generate PDF invoice': 'Regenerate PDF invoice'}}
translate> </vn-item>
Send CSV <vn-item
</vn-item> ng-click="$ctrl.showExportationLetter()"
</vn-list> ng-show="$ctrl.invoiceOut.serial == 'E'"
</vn-menu> translate>
</vn-item> Show CITES letter
<vn-item </vn-item>
ng-click="deleteConfirmation.show()" </vn-list>
vn-acl="invoicing"
vn-acl-action="remove"
name="deleteInvoice"
translate>
Delete Invoice
</vn-item>
<vn-item
ng-click="bookConfirmation.show()"
vn-acl="invoicing"
vn-acl-action="remove"
name="bookInvoice"
translate>
Book invoice
</vn-item>
<vn-item
ng-click="createInvoicePdfConfirmation.show()"
ng-show="$ctrl.hasInvoicing || !$ctrl.invoiceOut.hasPdf"
name="regenerateInvoice"
translate>
{{!$ctrl.invoiceOut.hasPdf ? 'Generate PDF invoice': 'Regenerate PDF invoice'}}
</vn-item>
<vn-item
ng-click="$ctrl.showExportationLetter()"
ng-show="$ctrl.invoiceOut.serial == 'E'"
translate>
Show CITES letter
</vn-item>
</vn-list>
</vn-menu> </vn-menu>
<vn-confirm <vn-confirm
vn-id="deleteConfirmation" vn-id="deleteConfirmation"
on-accept="$ctrl.deleteInvoiceOut()" on-accept="$ctrl.deleteInvoiceOut()"
question="Are you sure you want to delete this invoice?"> question="Are you sure you want to delete this invoice?">
</vn-confirm> </vn-confirm>
<vn-confirm <vn-confirm
vn-id="bookConfirmation" vn-id="bookConfirmation"
on-accept="$ctrl.bookInvoiceOut()" on-accept="$ctrl.bookInvoiceOut()"
question="Are you sure you want to book this invoice?"> question="Are you sure you want to book this invoice?">
</vn-confirm> </vn-confirm>
<vn-client-descriptor-popover <vn-client-descriptor-popover
vn-id="clientDescriptor"> vn-id="clientDescriptor">
</vn-client-descriptor-popover> </vn-client-descriptor-popover>
<!-- Create invoice PDF confirmation dialog --> <!-- Create invoice PDF confirmation dialog -->
<vn-confirm <vn-confirm
vn-id="createInvoicePdfConfirmation" vn-id="createInvoicePdfConfirmation"
on-accept="$ctrl.createPdfInvoice()" on-accept="$ctrl.createPdfInvoice()"
question="Are you sure you want to generate/regenerate the PDF invoice?" question="Are you sure you want to generate/regenerate the PDF invoice?"
message="Generate PDF invoice document"> message="Generate PDF invoice document">
</vn-confirm> </vn-confirm>
<!-- Send PDF invoice confirmation popup --> <!-- Send PDF invoice confirmation popup -->
<vn-dialog <vn-dialog
vn-id="sendPdfConfirmation" vn-id="sendPdfConfirmation"
on-accept="$ctrl.sendPdfInvoice($data)" on-accept="$ctrl.sendPdfInvoice($data)"
message="Send PDF invoice"> message="Send PDF invoice">
<tpl-body> <tpl-body>
<span translate>Are you sure you want to send it?</span> <span translate>Are you sure you want to send it?</span>
<vn-textfield vn-one <vn-textfield vn-one
label="Email" label="Email"
ng-model="sendPdfConfirmation.data.email"> ng-model="sendPdfConfirmation.data.email">
</vn-textfield> </vn-textfield>
</tpl-body> </tpl-body>
<tpl-buttons> <tpl-buttons>
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/> <input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
<button response="accept" translate>Confirm</button> <button response="accept" translate>Confirm</button>
</tpl-buttons> </tpl-buttons>
</vn-dialog> </vn-dialog>
<!-- Send CSV invoice confirmation popup --> <!-- Send CSV invoice confirmation popup -->
<vn-dialog <vn-dialog
vn-id="sendCsvConfirmation" vn-id="sendCsvConfirmation"
on-accept="$ctrl.sendCsvInvoice($data)" on-accept="$ctrl.sendCsvInvoice($data)"
message="Send CSV invoice"> message="Send CSV invoice">
<tpl-body> <tpl-body>
<span translate>Are you sure you want to send it?</span> <span translate>Are you sure you want to send it?</span>
<vn-textfield vn-one <vn-textfield vn-one
label="Email" label="Email"
ng-model="sendCsvConfirmation.data.email"> ng-model="sendCsvConfirmation.data.email">
</vn-textfield> </vn-textfield>
</tpl-body> </tpl-body>
<tpl-buttons> <tpl-buttons>
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/> <input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
<button response="accept" translate>Confirm</button> <button response="accept" translate>Confirm</button>
</tpl-buttons> </tpl-buttons>
</vn-dialog> </vn-dialog>

View File

@ -88,19 +88,6 @@ class Controller extends Section {
}); });
} }
downloadDocuware() {
const options = {
ticketId: 3367050
};
return this.$http.post(`Docuwares/download`, options)
.then(() => {
const snackbarMessage = this.$t(
`The invoice PDF document has been downloaded`);
this.vnApp.showSuccess(snackbarMessage);
});
}
sendPdfInvoice($data) { sendPdfInvoice($data) {
if (!$data.email) if (!$data.email)
return this.vnApp.showError(this.$t(`The email can't be empty`)); return this.vnApp.showError(this.$t(`The email can't be empty`));

View File

@ -27,10 +27,10 @@
</vn-item> </vn-item>
<a class="vn-item" <a class="vn-item"
ng-if="$ctrl.hasDocuware" ng-if="$ctrl.hasDocuware"
href="api/Docuwares/{{$ctrl.ticket.id}}/download?access_token={{$ctrl.vnToken.token}}" href='api/Docuwares/{{$ctrl.ticket.id}}/download/deliveryClient/findTicket?access_token={{$ctrl.vnToken.token}}'
target="_blank" target="_blank"
translate> translate>
as DOCUWARE as PDF
</a> </a>
<vn-item <vn-item
ng-click="$ctrl.showCsvDeliveryNote()" ng-click="$ctrl.showCsvDeliveryNote()"

View File

@ -82,9 +82,9 @@ class Controller extends Section {
return this.$http.get(`Tickets/${this.ticketId}`, {filter}) return this.$http.get(`Tickets/${this.ticketId}`, {filter})
.then(res => this.ticket = res.data) .then(res => this.ticket = res.data)
.then(() => { .then(() => {
this.hasDocuware();
this.canStowaway(); this.canStowaway();
this.isTicketEditable(); this.isTicketEditable();
this.hasDocuware();
}); });
} }
@ -124,7 +124,11 @@ class Controller extends Section {
} }
hasDocuware() { hasDocuware() {
this.$http.get(`Docuwares/${this.id}/checkFile`) const params = {
fileCabinet: 'deliveryClient',
dialog: 'findTicket'
};
this.$http.post(`Docuwares/${this.id}/checkFile`, params)
.then(res => { .then(res => {
this.hasDocuware = res.data; this.hasDocuware = res.data;
}); });

View File

@ -206,7 +206,8 @@ describe('Ticket Component vnTicketDescriptorMenu', () => {
it('should make a query and show a success snackbar', () => { it('should make a query and show a success snackbar', () => {
jest.spyOn(controller.vnApp, 'showSuccess'); jest.spyOn(controller.vnApp, 'showSuccess');
$httpBackend.whenGET(`Tickets/16`).respond(); $httpBackend.whenPOST(`Docuwares/${ticket.id}/checkFile`).respond();
$httpBackend.whenGET(`Tickets/${ticket.id}`).respond();
$httpBackend.expectPOST(`InvoiceOuts/${ticket.invoiceOut.id}/createPdf`).respond(); $httpBackend.expectPOST(`InvoiceOuts/${ticket.invoiceOut.id}/createPdf`).respond();
controller.createPdfInvoice(); controller.createPdfInvoice();
$httpBackend.flush(); $httpBackend.flush();
@ -275,4 +276,12 @@ describe('Ticket Component vnTicketDescriptorMenu', () => {
}); });
}); });
}); });
describe('hasDocuware()', () => {
it('should call hasDocuware method', () => {
$httpBackend.whenPOST(`Docuwares/${ticket.id}/checkFile`).respond();
controller.hasDocuware();
$httpBackend.flush();
});
});
}); });