284 lines
8.3 KiB
Markdown
284 lines
8.3 KiB
Markdown
Creada: 13/05/2025
|
||
Hora: 16:14
|
||
Autor: DAVID ITEHUA XALAMIHUA
|
||
Email: davidix1991@gmail.com
|
||
|
||
|
||
|
||
```js
|
||
|
||
// URL AYUDA GENERAR PDF: https://xfanatical.com/blog/print-google-sheet-as-pdf-using-apps-script/
|
||
|
||
// CONFIGURACIÓN
|
||
const CONFIG = {
|
||
SHEETS: {
|
||
PDF: "pdf",
|
||
ALLOWED: ["Internacionales", "Nacionales"]
|
||
},
|
||
RANGES: {
|
||
PDF_EXPORT: "C1:H17",
|
||
OUTPUT: {
|
||
ID: "K2",
|
||
SHEET_NAME: "K3"
|
||
},
|
||
COUNTRY: "D3",
|
||
DOC_TYPE: "D4"
|
||
}
|
||
};
|
||
|
||
// FUNCIONES PRINCIPALES
|
||
|
||
function onOpen() {
|
||
try {
|
||
SpreadsheetApp.getUi()
|
||
.createMenu('PDF')
|
||
.addItem('Descargar PDF', 'downloadPdf')
|
||
.addItem('Enviar PDF', 'sendPdfEmail')
|
||
.addToUi();
|
||
validarVencimientos();
|
||
} catch (error) {
|
||
console.error("Error en onOpen:", error);
|
||
}
|
||
}
|
||
|
||
function sendPdfEmail() {
|
||
processPdfFlow('email');
|
||
}
|
||
|
||
function downloadPdf() {
|
||
processPdfFlow('download');
|
||
}
|
||
|
||
|
||
// NÚCLEO DEL PROCESO
|
||
function processPdfFlow(action) {
|
||
try {
|
||
if (!validateEnvironment()) return;
|
||
const {fileId, fileName} = generateAndSavePdf();
|
||
if (!fileId) throw new Error("Error al generar PDF");
|
||
switch(action) {
|
||
case 'email':
|
||
sendEmailWithAttachment(fileId, fileName);
|
||
break;
|
||
case 'download':
|
||
downloadFile(fileId);
|
||
break;
|
||
}
|
||
trashFile(fileId);
|
||
showAlert(`✅ PDF ${action === 'email' ? 'enviado' : 'descargado'} correctamente`);
|
||
} catch (error) {
|
||
showAlert(`❌ Error: ${error.message}`);
|
||
console.error(error);
|
||
}
|
||
}
|
||
|
||
// FUNCIONES DE APOYO
|
||
function validateEnvironment() {
|
||
const ss = SpreadsheetApp.getActiveSpreadsheet();
|
||
const activeSheet = ss.getActiveSheet();
|
||
const activeCell = activeSheet.getActiveCell();
|
||
if (!CONFIG.SHEETS.ALLOWED.includes(activeSheet.getName())) {
|
||
showAlert('Solo disponible en hojas "Internacionales" o "Nacionales"');
|
||
return false;
|
||
}
|
||
|
||
const idValue = activeSheet.getRange(`A${activeCell.getRow()}`).getValue();
|
||
if (!Number.isInteger(idValue)) {
|
||
showAlert("Seleccione un registro con ID numérico en columna A");
|
||
return false;
|
||
}
|
||
|
||
const pdfSheet = ss.getSheetByName(CONFIG.SHEETS.PDF);
|
||
if (!pdfSheet) {
|
||
showAlert(`No se encontró la hoja "${CONFIG.SHEETS.PDF}"`);
|
||
return false;
|
||
}
|
||
// Actualizar datos
|
||
pdfSheet.getRange(CONFIG.RANGES.OUTPUT.ID).setValue(idValue);
|
||
pdfSheet.getRange(CONFIG.RANGES.OUTPUT.SHEET_NAME).setValue(activeSheet.getName());
|
||
pdfSheet.autoResizeRows(2, 40);
|
||
SpreadsheetApp.flush();
|
||
return true;
|
||
}
|
||
|
||
function generateAndSavePdf() {
|
||
const ss = SpreadsheetApp.getActiveSpreadsheet();
|
||
const pdfSheet = ss.getSheetByName(CONFIG.SHEETS.PDF);
|
||
const range = pdfSheet.getRange(CONFIG.RANGES.PDF_EXPORT);
|
||
const exportUrl = `${ss.getUrl().replace(/\/edit.*$/, '')}/export?` + [
|
||
'exportFormat=pdf',
|
||
'format=pdf',
|
||
'size=LETTER',
|
||
'portrait=true',
|
||
'fitw=true',
|
||
'sheetnames=false',
|
||
'printtitle=false',
|
||
`gid=${pdfSheet.getSheetId()}`,
|
||
`r1=${range.getRow() - 1}`,
|
||
`r2=${range.getLastRow()}`,
|
||
`c1=${range.getColumn() - 1}`,
|
||
`c2=${range.getLastColumn()}`
|
||
].join('&');
|
||
|
||
const country = pdfSheet.getRange(CONFIG.RANGES.COUNTRY).getValue();
|
||
const docType = pdfSheet.getRange(CONFIG.RANGES.DOC_TYPE).getValue().replace(/\s+/g, '_');
|
||
const fileName = `${getFormattedDate()}_resumen_${country}_${docType}.pdf`;
|
||
const blob = UrlFetchApp.fetch(exportUrl, {
|
||
headers: { Authorization: `Bearer ${ScriptApp.getOAuthToken()}` }
|
||
}).getBlob().setName(fileName);
|
||
return {
|
||
fileId: DriveApp.createFile(blob).getId(),
|
||
fileName: fileName
|
||
};
|
||
}
|
||
|
||
|
||
|
||
// FUNCIONES DE UTILIDAD
|
||
function sendEmailWithAttachment(fileId, fileName) {
|
||
MailApp.sendEmail({
|
||
to: Session.getActiveUser().getEmail(),
|
||
subject: `📄 ${fileName}`,
|
||
body: "Documento PDF generado automáticamente desde Google Sheets.",
|
||
attachments: [DriveApp.getFileById(fileId).getBlob()],
|
||
name: "Sistema Automático de PDF"
|
||
});
|
||
|
||
}
|
||
|
||
function downloadFile(fileId) {
|
||
const html = HtmlService.createHtmlOutput(`
|
||
<script>
|
||
window.open('https://drive.google.com/uc?export=download&id=${fileId}', '_blank');
|
||
google.script.host.close();
|
||
</script>
|
||
`).setWidth(100).setHeight(50);
|
||
SpreadsheetApp.getUi().showModalDialog(html, "Descargando...");
|
||
}
|
||
|
||
function trashFile(fileId) {
|
||
try {
|
||
DriveApp.getFileById(fileId).setTrashed(true);
|
||
} catch (error) {
|
||
console.warn("No se pudo eliminar archivo:", error);
|
||
}
|
||
}
|
||
|
||
function getFormattedDate() {
|
||
const format = num => String(num).padStart(2, '0');
|
||
const now = new Date();
|
||
return `${format(now.getDate())}.${format(now.getMonth()+1)}.${now.getFullYear()}-${format(now.getHours())}.${format(now.getMinutes())}`;
|
||
}
|
||
|
||
function showAlert(message) {
|
||
SpreadsheetApp.getUi().alert(message);
|
||
}
|
||
|
||
// \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
|
||
// NOTIFICACIONES VENCIMIENTOS
|
||
// /////////////////////////////////////////////////////////////////////
|
||
|
||
// 1. Optimización de formatearFecha (más eficiente con array estático)
|
||
const MESES = ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'];
|
||
|
||
function formatearFecha(date) {
|
||
return !(date instanceof Date) || isNaN(date.getTime())
|
||
? "Fecha inválida"
|
||
: `${date.getDate().toString().padStart(2, '0')}/${MESES[date.getMonth()]}/${date.getFullYear()}`;
|
||
}
|
||
|
||
// 2. Función genérica para procesar hojas (DRY - Don't Repeat Yourself)
|
||
|
||
function procesarHoja(hoja, colFecha, colPais, colInstitucion) {
|
||
const rango = hoja.getRange(`${colFecha}2:${colFecha}${hoja.getLastRow()}`);
|
||
const valores = rango.getValues();
|
||
const hoy = new Date().setHours(0, 0, 0, 0);
|
||
const alertas = [];
|
||
|
||
valores.forEach(([valorFecha], i) => {
|
||
if (!(valorFecha instanceof Date) || isNaN(valorFecha.getTime())) return;
|
||
const fecha = new Date(valorFecha).setHours(0, 0, 0, 0);
|
||
const diferenciaDias = Math.floor((fecha - hoy) / 86400000);
|
||
if (diferenciaDias >= 0 && diferenciaDias <= 40) {
|
||
const fila = i + 2;
|
||
alertas.push({
|
||
dias: diferenciaDias,
|
||
texto: `${hoja.getRange(`${colPais}${fila}`).getValue()}\n${
|
||
hoja.getRange(`${colInstitucion}${fila}`).getValue()}\n${
|
||
formatearFecha(new Date(fecha))} (${diferenciaDias} días)`
|
||
});
|
||
}
|
||
});
|
||
return alertas;
|
||
}
|
||
|
||
// 3. onOpen optimizado
|
||
function validarVencimientos() {
|
||
const ui = SpreadsheetApp.getUi();
|
||
try {
|
||
const ss = SpreadsheetApp.getActiveSpreadsheet();
|
||
const [hojaInt, hojaNac] = ['Internacionales', 'Nacionales']
|
||
.map(nombre => ss.getSheetByName(nombre));
|
||
if (!hojaInt || !hojaNac) {
|
||
ui.alert("Error", "No se encontró alguna de las hojas requeridas", ui.ButtonSet.OK);
|
||
return;
|
||
}
|
||
|
||
const alertas = [
|
||
...procesarHoja(hojaInt, 'H', 'B', 'E'),
|
||
...procesarHoja(hojaNac, 'I', 'B', 'E')
|
||
].sort((a, b) => a.dias - b.dias);
|
||
|
||
if (alertas.length) {
|
||
ui.alert(`⚠️ Alertas de vencimiento (${alertas.length}) ⚠️`,
|
||
`📅 Vencimientos próximos (≤40 días):\n\n${
|
||
alertas.map(a => a.texto).join('\n\n')}`,
|
||
ui.ButtonSet.OK);
|
||
} else {
|
||
ui.alert("Sin alertas", "No hay vencimientos próximos", ui.ButtonSet.OK);
|
||
}
|
||
} catch (error) {
|
||
ui.alert("Error", error.message, ui.ButtonSet.OK);
|
||
console.error(error);
|
||
}
|
||
}
|
||
|
||
// \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
|
||
// FUNCIONES DIX EN HOJAS
|
||
// ///////////////////////////////////////////////////////////
|
||
|
||
function sh_download(idFile) {
|
||
return `https://drive.google.com/uc?export=download&id=${idFile}&confirm=no`;
|
||
}
|
||
|
||
function sh_view(idFile){
|
||
return `https://drive.google.com/file/d/${idFile}/view?usp=drive_link`;
|
||
}
|
||
// \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
|
||
// OTRAS
|
||
// ///////////////////////////////////////////////////////////
|
||
```
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|