Initial commit

This commit is contained in:
2026-07-27 14:53:04 +02:00
commit 4a07713dd7
8 changed files with 3561 additions and 0 deletions
+299
View File
@@ -0,0 +1,299 @@
const ExcelJS = require('exceljs');
const { PDFParse } = require('pdf-parse');
const { PDFDocument } = require('pdf-lib');
const readline = require('node:readline/promises');
const { stdin: input, stdout: output } = require('node:process');
const fs = require('fs');
const os = require('os');
const path = require('path');
const sfdc = require('./sfdc2');
require('dotenv').config();
let excelFile = process.argv[2];
let pdfFile = process.argv[3];
// excel1 => /Users/ddatinguinoo/Downloads/Estratto IPP 5 Sic.xlsx
// excel2 => /Users/ddatinguinoo/Downloads/Estratto Haccp IPP 5 (1).xlsx
// pdf1 => /Users/ddatinguinoo/Downloads/G-S IPP 5.pdf
// pdf2 => /Users/ddatinguinoo/Downloads/H IPP 5.pdf
const data = []; // contains the info of all the clients
const tempFilePath = [];
const authConfig = {
sfdcTokenFile: process.env.SFDC_TOKEN_FILE, // Path to store/retrieve OAuth tokens
sfdcClientId: process.env.SFDC_CLIENT_ID,
sfdcClientSecret: process.env.SFDC_CLIENT_SECRET
};
async function initializeSalesforceConnection() {
// sfdc.setProductionBaseUrl(); // or sfdc.setSandboxBaseUrl();
sfdc.setSandboxBaseUrl(); // Example: using sandbox
sfdc.setTokenFile(authConfig.sfdcTokenFile);
sfdc.setClientId(authConfig.sfdcClientId);
sfdc.setClientSecret(authConfig.sfdcClientSecret);
// Try to load existing token or initiate OAuth flow
if (!await sfdc.getSalesforceToken()) {
console.log('No token found. Initiating OAuth2 flow...');
// For command-line scripts where a browser can be opened:
await sfdc.initToken((loginUrl) => {
console.log(`Please open this URL to authenticate: ${loginUrl}`);
});
} else {
console.log('Token loaded successfully.');
}
// Ensure the access token is valid and refresh if necessary
await sfdc.checkToken();
console.log('Salesforce connection is ready.');
}
async function attachPdfToAccount(sfdc) {
let parser;
try {
let contentVersion;
for (let i = 0; i < tempFilePath.length; i++) {
// 1. Read the local PDF file and convert it to Base64
const pdfBuffer = fs.readFileSync(tempFilePath[i]); // pdfFilePath is tempFilePath
const base64Pdf = pdfBuffer.toString('base64');
parser = new PDFParse({ data: pdfBuffer });
try {
const result = await parser.getText();
let conditions = [];
const userID = result.text.match(/Codice fiscale:\s*([A-Za-z0-9]+)/i);
const codiceFiscale = userID ? userID[1].trim() : null;
if (codiceFiscale) {
conditions.push(`CF__c='${ codiceFiscale }'`);
}
const nameMatch = result.text.match(/Il\s+Sig\.\/La\s+Sig\.ra[ \t]+([A-Za-zÀ-ÿ']+(?:[ \t]+[A-Za-zÀ-ÿ']+)+)/i);
if (nameMatch) {
const rawName = nameMatch[1].trim(); // "Kan Jessica Shuk Yi"
const parts = rawName.split(/\s+/);
if (parts.length >= 2) {
const fullName = parts.join(' ');
const reversedName = [...parts.slice(1), parts[0]].join(' ');
conditions.push(`Name='${fullName}'`);
if (fullName !== reversedName) {
conditions.push(`Name='${reversedName}'`);
}
}
}
// use the soql comand to search in the database
const soql = `SELECT Id, Name FROM Account WHERE (${conditions.join(' OR ')}) ORDER BY CreatedDate DESC LIMIT 1`;
const result_soql = await sfdc.query(soql);
if (result_soql && result_soql.records && result_soql.records.length > 0) { // if we find something
contentVersion = await sfdc.create('ContentVersion', {
Title: `${ result_soql.records[0].Name }_Document.pdf`,
PathOnClient: `${ result_soql.records[0].Name }_Document.pdf`,
VersionData: base64Pdf, // Must be Base64 string
FirstPublishLocationId: result_soql.records[0].Id// Automatically creates the link to the Account!
});
}
}
finally {
if (parser) {
await parser.destroy();
}
}
}
console.log(`PDFs successfully attached!`);
} catch (error) {
console.error(`Error uploading PDF: `, error);
}
}
// here we create an Account for each client and upload their pdf file
async function uploadUserAccount() {
await initializeSalesforceConnection();
// now for each client we need to create an Account on Salesforce
try {
for (let i = 0; i < data.length; i++) {
const firstName = (data[i].NOME || '').toString().trim();
const lastName = (data[i].COGNOME || '').toString().trim();
let userData = {
Name: `${ firstName } ${ lastName }`.trim(),
CF__c: data[i].CODICE_FISCALE || null,
};
const newAccount = await sfdc.create('Account', userData); // it creates the Account
}
console.log('Accounts created successfully!');
}
catch (error) {
console.log('Something went wrong while creating the accounts: ', error);
}
}
// this is where i need to store each page in a common temporary pdf file
async function processPage(pdfDoc, pageIndex) {
try {
const newDoc = await PDFDocument.create();
const [ copiedPage ] = await newDoc.copyPages(pdfDoc, [pageIndex]);
newDoc.addPage(copiedPage);
const pdfBytes = await newDoc.save();
const filepath = path.join(os.tmpdir(), `fileTemp_page_${pageIndex}.pdf`);
fs.writeFileSync(filepath, pdfBytes);
tempFilePath.push(filepath);
}
catch (error) {
console.error('Error in processPage:', error);
}
}
async function splitExcelFile(inputFile) {
let numRows; // this parameter is needed when we need to analyze the pdf file in case it has duplicates
const columnNames = []; // contains the names of the columns (header names)
try {
console.log(`Loading excel file: ${ inputFile }\n`);
const workbook = new ExcelJS.Workbook();
await workbook.xlsx.readFile(inputFile);
const worksheet = workbook.getWorksheet(1);
const headerRow = worksheet.getRow(1).actualCellCount; //number of columns of the table
numRows = (worksheet.actualRowCount) - 1;
worksheet.getRow(1) // to convert every title of the first row to upper case
.eachCell((col, col_num) => {
if (typeof col.value === 'string') {
col.value = col.value.toUpperCase().trim();
}
})
// convert every letter of CF to uppercase and store the CFs in the array cf
if (worksheet.getRow(1).getCell(6).value.trim() === 'CODICE FISCALE') {
worksheet.getColumn(6)
.eachCell((row, row_num) => {
row.value = (row.value).toString().toUpperCase();
})
}
worksheet.getColumn(8) // of the first file
.eachCell((cell, rownumber) => {
if (typeof cell.value === 'string') {
cell.value = (cell.value).replace(/\b\w/g, char => char.toUpperCase());
/* \b finds the start of a word (the boundary of a word)
\w targets the first letter following that boundary
/g (global flag) ensures it updates every word
*/
}
})
// to store the names of the columns in columnNames
worksheet.getRow(1).eachCell((cell, cell_num) => {
columnNames.push(cell.value);
})
// now we need to store the data of each user
for (let i = 2; i <= numRows + 1; i++) {
let dataUser = {};
worksheet.getRow(i)
.eachCell((cell, cell_num) => {
const rawColumnName = columnNames[cell_num - 1] || `column_${cell_num}`;
// 1. Trim whitespace and replace spaces with underscores
const cleanKey = rawColumnName
.toString()
.trim()
.replace(/\s+/g, '_'); // \s => matches any whitespaces
// + => groups multiple consecutive spaces together into a
// single match so you don't end up with multiple underscores.
dataUser[cleanKey] = cell.value;
})
data.push(dataUser);
}
return numRows;
}
catch (error) {
console.error('Error processing the excel file: ', error);
}
}
async function splitPDF(numRows, inputFile) {
console.log(`Loading pdf file: ${ inputFile }...\n`);
let parser;
try {
// 1. we use pdfParse to read and extract the content of a pdf file
const existingPdfBytes = fs.readFileSync(inputFile);
parser = new PDFParse({ data: existingPdfBytes });
const result = await parser.getText();
const pagesNumber = result.pages.length; //pages number of the pdf file
// 2. we use pdf-lib to create and edit a pdf file
const srcPdf = await PDFDocument.load(existingPdfBytes);
// if there are duplicates (back to back duplicates), I only have to print one copy
if (pagesNumber > numRows) { // comparison between the number of pages of the pdf file and those of the excel file
let displayNumPage = 1;
let i;
for (i = 1; i < pagesNumber && displayNumPage <= numRows; i += 2) {
if (result.pages[i].text.trim() === result.pages[i - 1].text.trim()) {
continue;
}
/*console.log(`--- PAGE ${ displayNumPage } ---`);
console.log(result.pages[i].text);
console.log("\n");*/
await processPage(srcPdf, i);
displayNumPage++;
}
}
else {
for (let i = 0; i < pagesNumber; i++) {
/*console.log(`--- PAGE ${i + 1} ---`);
console.log(result.pages[i].text);
console.log("\n");*/
await processPage(srcPdf, i); // Pass 0-based index i
}
}
}
catch (error) {
console.error(`Error processing the pdf file: `, error);
}
finally {
if (parser) {
await parser.destroy();
}
}
}
async function main() {
const result = await splitExcelFile(excelFile);
await splitPDF(result, pdfFile);
const rl = readline.createInterface({ input, output });
let reply = '';
try {
while(!reply) {
const response = await rl.question('Do you want to create accounts or upload pages (accounts/pages)? ');
reply = response.trim();
if (!reply) {
console.log('Please try again!');
}
}
if (reply === 'accounts') {
await uploadUserAccount();
}
else if (reply === 'pages') {
await initializeSalesforceConnection();
await attachPdfToAccount(sfdc);
}
}
finally {
rl.close();
}
}
main();