582 lines
20 KiB
JavaScript
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}`));
|