Files
bodyshop/server/esign/esign-new.js
2026-02-27 13:15:10 -08:00

237 lines
9.3 KiB
JavaScript

const { Documenso } = require("@documenso/sdk-typescript");
const axios = require("axios");
const { jsrAuthString } = require("../utils/utils");
const DOCUMENSO_API_KEY = "api_asojim0czruv13ud";//Done on a by team basis,
const documenso = new Documenso({
apiKey: DOCUMENSO_API_KEY,//Done on a by team basis,
serverURL: "https://stg-app.documenso.com/api/v2",
});
const jsreport = require("@jsreport/nodejs-client");
async function distributeDocument(req, res) {
try {
const { documentId } = req.body;
const distributeResult = await documenso.documents.distribute({
documentId,
});
res.json({ success: true, distributeResult });
} catch (error) {
console.error("Error distributing document:", error?.data);
res.status(500).json({ error: "An error occurred while distributing the document." });
}
}
async function newEsignDocument(req, res) {
try {
const client = req.userGraphQLClient;
const { pdf: fileBuffer, esigFields } = await RenderTemplate({ client, req })
const fileBlob = new Blob([fileBuffer], { type: "application/pdf" });
const createDocumentResponse = await documenso.documents.create({
payload: {
title: `Repair Authorization - ${new Date().toLocaleString()}`,
recipients: [
{
email: "patrick.fic@convenient-brands.com",
name: "Customer Fullname",
role: "SIGNER",
}
],
meta: {
timezone: "America/Vancouver",
dateFormat: "MM/dd/yyyy hh:mm a",
language: "en",
subject: "Repair Authorization for ABC Collision",
message: "To perform repairs on your vehicle, we must receive digital authorization. Please review and sign the document to proceed with repairs. ",
}
},
file: fileBlob
});
const documentResult = await documenso.documents.get({
documentId: createDocumentResponse.id,
});
if (esigFields && esigFields.length > 0) {
console.log("Adding placeholder fields.")
try {
// await axios.post(`https://stg-app.documenso.com/api/v2/envelope/field/create-many`, {
// envelopeId: createDocumentResponse.envelopeId,
// data: esigFields.map(sigField => ({ ...sigField, recipientId: result.recipients[0].id, }))
// }, {
// headers: {
// Authorization: DOCUMENSO_API_KEY
// }
// })
const fieldResult = await documenso.envelopes.fields.createMany({
envelopeId: createDocumentResponse.envelopeId,
data: esigFields.map(sigField => ({ ...sigField, recipientId: documentResult.recipients[0].id, }))
});
} catch (error) {
console.log("Error adding placeholders", JSON.stringify(error, null, 2));
}
}
const presignToken = await documenso.embedding.embeddingPresignCreateEmbeddingPresignToken({})
res.json({ token: presignToken.token, documentId: createDocumentResponse.id, envelopeId: createDocumentResponse.envelopeId });
}
catch (error) {
console.error("Error in newEsignDocument:", error);
res.status(500).json({ error: "An error occurred while creating the e-sign document." });
}
}
async function RenderTemplate({ req }) {
//TODO Refactor to pull
const jsrAuth = jsrAuthString()
const jsreportClient = new jsreport("https://reports.test.imex.online", process.env.JSR_USER, process.env.JSR_PASSWORD);
const { templateObject, bodyshop } = req.body;
let { contextData, useShopSpecificTemplate, shopSpecificFolder, esigFields } = await fetchContextData({ templateObject, jsrAuth, req });
//TODO - Refactor to pull template content and render on server instead of posting back to client for rendering. This is necessary to get the rendered PDF buffer that we can then upload to Documenso.
const { ignoreCustomMargins } = { ignoreCustomMargins: false }// Templates[templateObject.name];
let reportRequest = {
template: {
name: useShopSpecificTemplate ? `/${bodyshop.imexshopid}/${templateObject.name}` : `/${templateObject.name}`,
recipe: "chrome-pdf",
...(!ignoreCustomMargins && {
chrome: {
marginTop:
bodyshop.logo_img_path &&
bodyshop.logo_img_path.headerMargin &&
bodyshop.logo_img_path.headerMargin > 36
? bodyshop.logo_img_path.headerMargin
: "36px",
marginBottom:
bodyshop.logo_img_path &&
bodyshop.logo_img_path.footerMargin &&
bodyshop.logo_img_path.footerMargin > 50
? bodyshop.logo_img_path.footerMargin
: "50px"
}
}),
},
data: {
...contextData,
...templateObject.variables,
...templateObject.context,
headerpath: shopSpecificFolder ? `/${bodyshop.imexshopid}/header.html` : `/GENERIC/header.html`,
footerpath: shopSpecificFolder ? `/${bodyshop.imexshopid}/footer.html` : `/GENERIC/footer.html`,
bodyshop: bodyshop,
filters: templateObject?.filters,
sorters: templateObject?.sorters,
offset: bodyshop.timezone, //dayjs().utcOffset(),
defaultSorters: templateObject?.defaultSorters
}
};
const render = await jsreportClient.render(reportRequest);
//Check render object and download. It should be the PDF?
const pdfBuffer = await render.body()
return { pdf: pdfBuffer, esigFields }
}
const fetchContextData = async ({ templateObject, jsrAuth, req, }) => {
const { bodyshop } = req.body
const server = "https://reports.test.imex.online";
//jsreport.headers["FirebaseAuthorization"] = req.headers.authorization;
const folders = await axios.get(`${server}/odata/folders`, {
headers: { Authorization: jsrAuth }
});
const shopSpecificFolder = folders.data.value.find((f) => f.name === bodyshop.imexshopid);
const jsReportQueries = await axios.get(
`${server}/odata/assets?$filter=name eq '${templateObject.name}.query'`,
{ headers: { Authorization: jsrAuth } }
);
const jsReportEsig = await axios.get(
`${server}/odata/assets?$filter=name eq '${templateObject.name}.esig'`,
{ headers: { Authorization: jsrAuth } }
);
let templateQueryToExecute;
let esigFields;
let useShopSpecificTemplate = false;
// let shopSpecificTemplate;
if (shopSpecificFolder) {
let shopSpecificTemplate = jsReportQueries.data.value.find(
(f) => f?.folder?.shortid === shopSpecificFolder.shortid
);
if (shopSpecificTemplate) {
useShopSpecificTemplate = true;
templateQueryToExecute = atob(shopSpecificTemplate.content);
}
let shopSpecificEsig = jsReportEsig.data.value.find(
(f) => f?.folder?.shortid === shopSpecificFolder.shortid
);
if (shopSpecificEsig) {
esigFields = (atob(shopSpecificEsig.content));
}
}
if (!templateQueryToExecute) {
const generalTemplate = jsReportQueries.data.value.find((f) => !f.folder);
useShopSpecificTemplate = false;
templateQueryToExecute = atob(generalTemplate.content);
}
if (!esigFields) {
const generalTemplate = jsReportEsig.data.value.find((f) => !f.folder);
useShopSpecificTemplate = false;
if (generalTemplate && generalTemplate.content) {
esigFields = atob(generalTemplate?.content);
}
}
// Commented out for future revision debugging
// console.log('Template Object');
// console.dir(templateObject);
// console.log('Unmodified Query');
// console.dir(templateQueryToExecute);
// const hasFilters = templateObject?.filters?.length > 0;
// const hasSorters = templateObject?.sorters?.length > 0;
// const hasDefaultSorters = templateObject?.defaultSorters?.length > 0;
const client = req.userGraphQLClient;
// In the print center, we will never have sorters or filters.
// We have no template filters or sorters, so we can just execute the query and return the data
// if (!hasFilters && !hasSorters && !hasDefaultSorters) {
let contextData = {};
if (templateQueryToExecute) {
const data = await client.request(
templateQueryToExecute,
templateObject.variables,
);
contextData = data;
}
return {
contextData,
useShopSpecificTemplate,
shopSpecificFolder,
esigFields: esigFields ? JSON.parse(esigFields) : [] //TODO: Do the parsing earlier and harden this. Causes a lot of failures on mini format issues.
};
// }
// return await generateTemplate(templateQueryToExecute, templateObject, useShopSpecificTemplate, shopSpecificFolder);
};
module.exports = {
newEsignDocument,
distributeDocument
}