word-doc-generator/server.js

582 lines
20 KiB
JavaScript

const express = require('express');
const bodyParser = require('body-parser');
const fs = require('fs');
const path = require('path');
const PizZip = require('pizzip');
const vCard = require('vcf');
const Docxtemplater = require('docxtemplater');
const ExcelJS = require('exceljs');
const ics = require('ics');
const dayjs = require('dayjs');
const advancedFormat = require('dayjs/plugin/advancedFormat');
const numberToWords = require('number-to-words');
const { fieldToCellMap } = require('./constants');
// Define directoryPath for Client Folder Location
// Define possible directory paths
const linuxPath = '/mnt/DropBox/clients';
const windowsPath = 'D:\\Bklistservinfo Dropbox\\Ryan Callahan\\clients';
// Function to check if a directory exists and is accessible
function isDirectoryAccessible(path) {
try {
if (!fs.existsSync(path)) {
console.log(`Path does not exist: ${path}`);
return false;
}
if (!fs.statSync(path).isDirectory()) {
console.log(`Path is not a directory: ${path}`);
return false;
}
fs.accessSync(path, fs.constants.W_OK);
return true;
} catch (err) {
console.log(`No access to path: ${path}, Error: ${err.message}`);
return false;
}
}
// Use the Linux path if it's accessible; otherwise, fallback to Windows path
const directoryPath = isDirectoryAccessible(linuxPath) ? linuxPath : windowsPath;
console.log(`Using directory path: ${directoryPath}`);
dayjs.extend(advancedFormat);
let today = dayjs();
console.log(today.format('MMMM Do, YYYY')); // Output: July 14th, 2023
const app = express();
// Default to root for local dev — set BASE_PATH to "/" locally or to "/your-base" behind Apache
const BASE_PATH = process.env.BASE_PATH || '/';
const router = express.Router();
// Apply JSON/body-parser and static middleware to the router so routes are mounted under BASE_PATH
router.use(bodyParser.json());
router.use(express.json()); // Middleware to parse JSON bodies
router.use(express.static(path.join(__dirname, 'public')));
function generateDocument(data, documentPath) {
let content = fs.readFileSync(
path.resolve(__dirname, documentPath),
'binary'
);
let zip = new PizZip(content);
let doc = new Docxtemplater();
doc.loadZip(zip);
doc.setData(data);
try {
doc.render();
} catch (error) {
var e = {
message: error.message,
name: error.name,
stack: error.stack,
properties: error.properties,
};
console.log(JSON.stringify({ error: e }));
throw error;
}
return doc.getZip().generate({ type: 'nodebuffer' });
}
async function generateClientFolder(data) {
const folderPath = directoryPath; // Path for the folder
// Check if directoryPath exists
if (!fs.existsSync(folderPath)) {
console.error(`Error: The directory path ${folderPath} does not exist.`);
return; // Exit the function without crashing the code
}
const subFolderPath = path.join(folderPath, `${data.clientLastName}, ${data.clientFirstName}`); // Path for the subfolder
const subfolderCasePath = path.join(subFolderPath, `${data.caseNumber}_${data.casePlaintiffFileName}`); // Path for the case subfolder
// Check if the main "client" folder exists
if (!fs.existsSync(folderPath)) {
// If it doesn't exist, create the "client" folder
fs.mkdirSync(folderPath, { recursive: true });
console.log(`Folder created at: ${folderPath}`);
}
// Check if the subfolder for the client exists
if (!fs.existsSync(subFolderPath)) {
// If it doesn't exist, create the subfolder
fs.mkdirSync(subFolderPath, { recursive: true });
console.log(`Subfolder created at: ${subFolderPath}`);
} else {
console.log(`Subfolder already exists at: ${subFolderPath}`);
}
// Check if the case documents subfolder exists
if (!fs.existsSync(subfolderCasePath)) {
// If it doesn't exist, create the case documents subfolder
fs.mkdirSync(subfolderCasePath, { recursive: true });
console.log(`Case documents subfolder created at: ${subfolderCasePath}`);
} else {
console.log(`Case documents subfolder already exists at: ${subfolderCasePath}`);
}
/* Dynamically import the 'open' module and open the subfolder
try {
const open = (await import('open')).default;
await open(subFolderPath);
console.log(`Opened ${subFolderPath}`);
} catch (err) {
console.error(`Failed to open ${subFolderPath}:`, err);
}
*/
}
function createVCard(data) {
let card = new vCard();
// Set the fields in the vCard
card.set(
'fn',
`${data.clientFirstName} ${data.clientMiddleName} ${data.clientLastName} ${data.clientNameSuffix}`
);
card.set(
'n',
`${data.clientLastName};${data.clientFirstName};${data.clientMiddleName};;${data.clientNameSuffix}`
);
card.set('email', data.email);
card.add('tel', data.homePhone, { type: 'home' });
card.add('tel', data.cellPhone, { type: 'cell' });
card.add(
'adr',
`;;${data.homeAddress};${data.homeCity};${data.homeState};${data.homeZip}`,
{ type: 'home' }
); // Set the 'adr' field with a type of 'home'
card.set('bday', data.dob);
card.set(
'note',
`Representation on ${data.casePlaintiff} v. ${data.caseDefendant}, ${data.caseNumber}`
);
card.set('org', `Clients - ${data.homeState}`);
return card.toString();
}
async function generateExcel(data) {
const workbook = new ExcelJS.Workbook();
await workbook.xlsx.readFile(path.resolve(__dirname, 'template.xlsx'));
const worksheet = workbook.getWorksheet(1);
for (let field in fieldToCellMap) {
if (fieldToCellMap.hasOwnProperty(field) && data.hasOwnProperty(field)) {
worksheet.getCell(fieldToCellMap[field]).value = data[field];
}
}
return await workbook.xlsx.writeBuffer();
}
router.post('/generate-excel', async (req, res) => {
const data = req.body;
let buf = await generateExcel(data);
let filename = `${data.clientLastName}-${data.clientFirstName}_${data.caseNumber}_Data.xlsx`;
res.setHeader(
'Content-Type',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
);
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
res.send(buf);
});
router.post('/generate-ics', (req, res) => {
const data = req.body;
const eventName = `${data.casePlaintiff} v. ${data.caseDefendant}`;
const location = `${data.caseCounty} County ${data.caseDesignation} Court, Div ${data.caseDivisionNumber}`;
const startDateArray = dayjs(data.caseAnswerDate)
.format('YYYY-M-D-H-m')
.split('-')
.map(Number);
const endDateArray = dayjs(data.caseAnswerDate)
.add(30, 'minute')
.format('YYYY-M-D-H-m')
.split('-')
.map(Number);
// Create the HTML table
const description = `Case No: ${data.caseNumber}\t Client Name: ${data.clientFirstName} ${data.clientLastName}
Appearance Information: Judge: ${data.caseDivisionJudge}; Suit Amount: $${data.caseSuitAmount};
Case Information: First Court Date: ${data.caseAnswerDate}; Opposing Counsel: ${data.caseOpposingCounsel}; Suit Theory: ${data.caseSuitTheory}`;
const { error, value } = ics.createEvent({
start: startDateArray,
end: endDateArray,
title: eventName,
description: description, // Add the description here
location: location,
});
if (error) {
console.log(error);
return res.status(500).send({ error });
}
let filename = `${eventName}.ics`;
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
res.send(value);
});
router.post('/generate-MOdisco-ics', (req, res) => {
const data = req.body;
// Get the Discovery CoS Date from the request body
const discoCosDate = data.discoCosDate;
// Parse the Discovery CoS Date and add 30 days to get the discovery response date
const discoveryResponseDate = dayjs(discoCosDate).add(30, 'days');
const startDateArray = discoveryResponseDate
.format('YYYY-M-D')
.split('-')
.map(Number);
const endDateArray = discoveryResponseDate
.add(1, 'day')
.format('YYYY-M-D')
.split('-')
.map(Number);
// Set the event title, description, and location
const eventName = `DISCO due on ${data.casePlaintiff} v. ${data.caseDefendant}, ${data.caseNumber}`;
const description = `CoS Date: ${discoCosDate}`; // Add the CoD Date to the description
const location = `${data.caseCounty} County ${data.caseDesignation} Court, Div ${data.caseDivisionNumber}`;
const { error, value } = ics.createEvent({
start: startDateArray,
end: endDateArray,
title: eventName,
description: description,
location: location,
});
if (error) {
console.log(error);
return res.status(500).send({ error });
}
let filename = `${eventName}.ics`;
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
res.send(value);
});
router.post('/generate-KSdisco-ics', (req, res) => {
const data = req.body;
// Get the Discovery CoS Date from the request body
const discoCosDate = data.discoCosDate;
// Parse the Discovery CoS Date and add 30 days to get the discovery response date
const discoveryResponseDate = dayjs(discoCosDate).add(14, 'days');
const startDateArray = discoveryResponseDate
.format('YYYY-M-D')
.split('-')
.map(Number);
const endDateArray = discoveryResponseDate
.add(1, 'day')
.format('YYYY-M-D')
.split('-')
.map(Number);
// Set the event title, description, and location
const eventName = `DISCO due on ${data.casePlaintiff} v. ${data.caseDefendant}, ${data.caseNumber}`;
const description = `CoS Date: ${discoCosDate}`; // Add the CoD Date to the description
const location = `${data.caseCounty} County ${data.caseDesignation} Court, Div ${data.caseDivisionNumber}`;
const { error, value } = ics.createEvent({
start: startDateArray,
end: endDateArray,
title: eventName,
description: description,
location: location,
});
if (error) {
console.log(error);
return res.status(500).send({ error });
}
let filename = `${eventName}.ics`;
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
res.send(value);
});
router.post('/generate-vCard', (req, res) => {
const data = req.body; // This is your form data
let vCardString = createVCard(data);
let filename = `${data.caseNumber}-contact.vcf`; // Modify this line to use your desired filename
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
res.type('text/vcard');
res.send(vCardString);
});
router.post('/generate-reminder-ics', (req, res) => {
const data = req.body;
// Get the current date
const today = dayjs();
// Add 45 days to the current date
const futureDate = today.add(45, 'days');
const startDateArray = futureDate
.format('YYYY-M-D')
.split('-')
.map(Number);
const endDateArray = futureDate
.add(1, 'day')
.format('YYYY-M-D')
.split('-')
.map(Number);
// Set the event title, description, and location
const todayDate = dayjs().format('MM/DD/YYYY');
const eventName = `REMINDER - ${data.clientFirstName} ${data.clientLastName} - Check Credit Dispute Reporting`;
let description = `FDCPA Disputes were mailed on ${todayDate} to:\n`;
for (let i = 1; i <= 9; i++) {
let name = data[`debtCollector${i}Name`];
let creditor = data[`debtCollector${i}Creditor`];
let account = data[`debtCollector${i}Account`];
let amount = data[`debtCollector${i}Amount`];
if (name) {
description += `- ${name} \n \tregarding a ${creditor} account (Acc. No. ${account}) for $${amount},\n`;
}
}
// Remove the last comma and newline
description = description.trim().slice(0, -1);
const { error, value } = ics.createEvent({
start: startDateArray,
end: endDateArray,
title: eventName,
description: description,
});
if (error) {
console.log(error);
return res.status(500).send({ error });
}
let filename = `${eventName}.ics`;
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
res.send(value);
});
router.post('/generate-vCard', (req, res) => {
const data = req.body; // This is your form data
let vCardString = createVCard(data);
let filename = `${data.caseNumber}-contact.vcf`; // Modify this line to use your desired filename
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
res.type('text/vcard');
res.send(vCardString);
});
router.post('/generate-ics-body', (req, res) => {
const data = req.body;
let buf = generateDocument(data, 'isc-body.docx');
let filename = `${data.caseNumber}-ics-body.docx`;
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
res.send(buf);
});
router.post('/generate-retainer', (req, res) => {
const data = req.body;
let buf = generateDocument(data, 'retainer.docx');
let filename = `${data.clientLastName}-${data.clientFirstName}_${data.caseNumber}_Representation-and-Fee-Agreement.docx`;
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
res.send(buf);
});
router.post('/generate-eoa', (req, res) => {
const data = req.body;
let buf = generateDocument(data, 'entry.docx');
let filename = `${data.caseNumber}_EoA.docx`;
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
res.send(buf);
});
router.post('/generate-notes', (req, res) => {
const data = req.body;
let buf = generateDocument(data, 'notes.docx');
let filename = `${data.clientLastName}-${data.clientFirstName} - Intake and Notes.docx`;
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
res.send(buf);
});
router.post('/generate-spreadsheet', (req, res) => {
const data = req.body;
let buf = generateDocument(data, 'spreadsheets.docx');
let filename = `${data.clientLastName}-${data.clientFirstName}_Spreadsheets.docx`;
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
res.send(buf);
});
router.post('/generate-ADs', (req, res) => {
const data = req.body;
let buf = generateDocument(data, 'defenses.docx');
let filename = `${data.caseNumber}_Affirmative-Defenses.docx`;
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
res.send(buf);
});
router.post('/generate-closeout', (req, res) => {
const data = req.body;
let buf = generateDocument(data, 'closeout.docx');
let filename = `${data.caseNumber}_${data.clientLastName}_Closeout-Letter.docx`;
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
res.send(buf);
});
router.post('/generate-closeout-with-costs', (req, res) => {
const data = req.body;
let buf = generateDocument(data, 'closeout_CJ_with-interest-costs.docx');
let filename = `${data.caseNumber}_${data.clientLastName}_Closeout.docx`;
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
res.send(buf);
});
router.post('/generate-waiver', (req, res) => {
const data = req.body;
let buf = generateDocument(data, 'waiver.docx');
let filename = `${data.caseNumber}_Service-Waiver.docx`;
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
res.send(buf);
});
router.post('/generate-pleading', (req, res) => {
const data = req.body;
let templateName = data.templateName; // This should be sent from the client side
if (!templateName) {
res.status(400).send('Template name is required');
return;
}
let templatePath = path.join(__dirname, 'Pleadings', `${templateName}.docx`);
let buf = generateDocument(data, templatePath);
let filename = `${data.caseNumber}_Pleading.docx`;
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
res.send(buf);
});
router.post('/generate-disco', (req, res) => {
const data = req.body;
let templateName = data.templateName; // This should be sent from the client side
if (!templateName) {
res.status(400).send('Template name is required');
return;
}
let templatePath = path.join(__dirname, 'Discovery', `${templateName}.docx`);
let buf = generateDocument(data, templatePath);
let filename = `${data.caseNumber}_Disco-Responses.docx`;
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
res.send(buf);
});
router.post('/generate-letter', (req, res) => {
const data = req.body;
let templateName = data.templateName; // This should be sent from the client side
if (!templateName) {
res.status(400).send('Template name is required');
return;
}
let templatePath = path.join(__dirname, 'Letters', `${templateName}.docx`);
let buf = generateDocument(data, templatePath);
let filename = `${data.clientLastName}-${data.clientFirstName}_${data.caseNumber}_Letter.docx`;
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
res.send(buf);
});
router.post('/generate-Canned-Emails', (req, res) => {
const data = req.body;
let buf = generateDocument(data, 'Canned-Emails.docx');
let filename = `${data.caseNumber}_Canned-Emails.docx`;
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
res.send(buf);
});
router.post('/generate-Dispute-Letter', (req, res) => {
const data = req.body;
let buf = generateDocument(data, 'letter.docx');
let date = dayjs().format('YYYY-MM-DD');
let filename = `${data.clientLastName}_FDCPA-Disputes_${date}.docx`;
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
res.send(buf);
});
router.post('/generate-Dispute-Envelope', (req, res) => {
const data = req.body;
let buf = generateDocument(data, 'dispute-envelopes.docx');
let date = dayjs().format('YYYY-MM-DD');
let filename = `${data.clientLastName}_FDCPA-Disputes_${date}_Envelopes.docx`;
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
res.send(buf);
});
router.post('/generate-Dispute-Cert', (req, res) => {
const data = req.body;
let buf = generateDocument(data, 'cert-mailing.docx');
let date = dayjs().format('YYYY-MM-DD');
let filename = `${data.clientLastName}_FDCPA-Disputes_${date}_Mail-Cert.docx`;
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
res.send(buf);
});
router.post('/generate-client-folder', (req, res) => {
const data = req.body;
let buf = generateClientFolder(data);
res.send(buf);
});
router.post('/generate-credit-auth', (req, res) => {
const data = req.body;
let buf = generateDocument(data, 'authorization-disclosure.docx');
let filename = `${data.clientLastName}-${data.clientFirstName}_Credit-Authorization.docx`;
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
res.send(buf);
});
router.post('/generate-credit-auth-no-payment', (req, res) => {
const data = req.body;
let buf = generateDocument(data, 'authorization-disclosure-no-payment.docx');
let filename = `${data.clientLastName}-${data.clientFirstName}_Credit-Authorization-No-Payment.docx`;
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
res.send(buf);
});
// Mount router under BASE_PATH
if (BASE_PATH === '/') {
app.use('/', router); // local dev
} else {
app.use(BASE_PATH, router); // behind Apache or with a base path
}
const PORT = process.env.PORT || 3001;
app.listen(PORT, '0.0.0.0', () => console.log(`Server is running and accessible on ${BASE_PATH} at port ${PORT}`));