Busca en Drive las subcarpetas con formato 278 - Nombre Acreedor
dentro de la carpeta del expediente y las vincula automáticamente a cada acreedor importado.
Solo vincula los acreedores que aún no tienen carpeta asignada.
📄 Vincular PDFs guardados en Drive
Busca en la carpeta de PDFs los archivos con formato 1ON - DERMAN MARTÍN - Informe Individual.pdf
y los vincula automáticamente a cada acreedor.
Solo vincula los acreedores que aún no tienen PDF asignado.
📂 Vincular carpetas Legajos Concursada
Busca en la carpeta Concurso Preventivo - Legajos Concursada las subcarpetas con formato
600 - TAE ALMADA S.A o
1FI - ADCAP SECURITIES
y las vincula a cada acreedor para acceso rápido desde el informe.
Solo vincula los acreedores que aún no tienen carpeta de concursada asignada.
📥 Importar Acreedores desde Drive (Google Sheets)
📋 Estructura esperada del Google Sheet
El Sheet debe tener 4 solapas: AntoAgusFloMarce
Columnas reconocidas: LEGAJO · INFORME_INDIVIDUAL · CORREO_ELECTRONICO · FECHA_Y_HORA_DE_RECEPION_MAIL · ACREEDOR · CUIT_ DNI · REPRESENTANTE · RELACION · DOMICILIO_REAL · LOCALIDAD · PROVINCIA · DOMICILIO_CONTITUIDO · LOCALIDAD_C · PROVINCIA_C · CP · PESOS · MONTO_SOLICITADO_$ · DOLAR · MONTO_SOLICITADO_U$D · EUROS · MONTO_SOLICITADO_EUROS · REALES · CAUSA · PRIVILEGIO · ARANCEL · F._PAGO_ARANCEL · DENUNCIADO? · ENVIO RC OFICIAL · OBSERVAC
Al importar, los acreedores se asignan automáticamente al usuario que corresponde según la solapa del Sheet. Los existentes se actualizan, los nuevos se agregan.
📋 Código Apps Script para el Google Sheet
Pegar en el Sheet → Extensiones → Apps Script. Luego implementar como App web.
// Apps Script — Exportar acreedores + Buscar carpetas Drive · Art.35 LCQ
// Solapas: Anto | Agus | Flo | Marce
// ► Pegar en: Extensiones → Apps Script → Implementar → App web
// Ejecutar como: Yo | Acceso: Cualquiera
const SHEET_USERS = ['Anto', 'Agus', 'Flo', 'Marce'];
// ⚠ ID de la carpeta raíz de Drive donde están las subcarpetas de legajos
const ROOT_FOLDER_ID = '1aRxZ09Ur0HD89_gudoIrog8h9UsSRMqk';
function doGet(e) {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const usuario = (e.parameter.usuario || '').trim();
const action = (e.parameter.action || '').trim();
// ── Buscar carpeta de un legajo en Drive ──
// Llamar con: ?action=buscarCarpeta&nleg=595&acreedor=SUMINOX+SRL&folderId=ID_CARPETA
if (action === 'buscarCarpeta') {
const nleg = (e.parameter.nleg || '').trim();
const acreedor = (e.parameter.acreedor || '').trim();
const folderId = (e.parameter.folderId || ROOT_FOLDER_ID).trim();
if (!nleg) return resp({ error: 'Falta parámetro nleg' });
if (!folderId || folderId === 'PEGAR_AQUI_ID_CARPETA_RAIZ') return resp({ error: 'Configurar el ID de la carpeta raíz de legajos en la aplicación (⚙ Configuración → Drive).' });
return resp(buscarCarpetaLegajo(nleg, acreedor, folderId));
}
// ── Buscar cheque por número en solapa del sheet activo ──
// Llamar con: ?action=buscarCheque&nro=12345678
if (action === 'buscarCheque') {
var nroBusc = (e.parameter.nro || '').trim();
if (!nroBusc) return resp({ ok: false, error: 'Falta número de cheque' });
try {
// Buscar la solapa de cheques en el sheet activo (mismo donde está el script)
var tabChq = ss.getSheetByName('cheques rechazados')
|| ss.getSheetByName('Cheques rechazados')
|| ss.getSheetByName('Cheques Rechazados')
|| ss.getSheetByName('CHEQUES RECHAZADOS EN CUENTAS PERSONALES')
|| ss.getSheetByName('CHEQUES RECHAZADOS')
|| ss.getSheetByName('Cheques')
|| ss.getSheetByName('cheques');
if (!tabChq) {
var solapas = ss.getSheets().map(function(s){ return s.getName(); }).join(', ');
return resp({ ok: false, error: 'Solapa de cheques no encontrada. Solapas del sheet: ' + solapas });
}
var datosChq = tabChq.getDataRange().getValues();
if (datosChq.length < 2) return resp({ ok: false, error: 'Hoja sin datos' });
var hdrs = datosChq[0].map(function(h){ return String(h||'').toLowerCase().trim().replace(/\s+/g,' '); });
var iNro=-1, iFecha=-1, iMonto=-1, iCausa=-1;
hdrs.forEach(function(h,i){
if(iNro<0 && (h.includes('nro') || h.includes('número') || h.includes('numero') || h==='cheque')) iNro=i;
if(iFecha<0 && h==='fecha') iFecha=i;
if(iFecha<0 && h.includes('fecha') && !h.includes('pago')) iFecha=i;
if(iMonto<0 && (h.includes('monto') || h.includes('importe') || h.includes('valor'))) iMonto=i;
if(iCausa<0 && h.includes('causa')) iCausa=i;
});
if(iNro<0) iNro=0;
if(iFecha<0) iFecha=1;
if(iMonto<0) iMonto=2;
var nroBuscClean = nroBusc.replace(/\D/g,'');
for (var ri = 1; ri < datosChq.length; ri++) {
var fila = datosChq[ri];
var nroFila = String(fila[iNro]||'').trim().replace(/\.0+$/, '');
var nroFilaClean = nroFila.replace(/\D/g,'');
if (!nroFilaClean) continue;
if (nroFila === nroBusc || (nroBuscClean && nroFilaClean === nroBuscClean)) {
var fechaVal = fila[iFecha];
var fechaStr = '';
if (fechaVal instanceof Date) {
fechaStr = Utilities.formatDate(fechaVal, Session.getScriptTimeZone(), 'yyyy-MM-dd');
} else if (fechaVal) { fechaStr = String(fechaVal).trim(); }
var montoVal = typeof fila[iMonto] === 'number' ? fila[iMonto] :
parseFloat(String(fila[iMonto]||'0').replace(/\./g,'').replace(',','.')) || 0;
var causaVal = iCausa>=0 ? String(fila[iCausa]||'').trim() : '';
return resp({ ok: true, encontrado: true, cheque: {
nro: nroFila, fecha: fechaStr, monto: montoVal.toFixed(2), banco: causaVal, causa: causaVal
}});
}
}
return resp({ ok: true, encontrado: false, totalFilas: datosChq.length-1,
solapaUsada: tabChq.getName(), headers: hdrs.slice(0,6).join(' | ') });
} catch(err2) {
return resp({ ok: false, error: err2.message });
}
}
// ── Leer tenencias de ON desde Excel externo ──
// Llamar con: ?action=leerExcelON&fileId=ID_EXCEL&nleg=5420ON
if (action === 'leerExcelON') {
// Lee desde Google Sheet Verificado — col A=nleg, J-O=VN por clase, P-U=cap remanente
var SS_ON_ID = '1sP1zT4etsYtj8mmniGEREV_uuryHuRaM';
var nlegBuscar = (e.parameter.nleg || '').trim().toUpperCase();
var cuitBuscar = (e.parameter.cuit || '').trim().replace(/[-\s]/g,'');
if (!nlegBuscar && !cuitBuscar) return resp({ error: 'Falta nleg o cuit' });
try {
var ssON = SpreadsheetApp.openById(SS_ON_ID);
var tabV = ssON.getSheetByName('Verificado');
if (!tabV) return resp({ error: 'Solapa Verificado no encontrada' });
var datos = tabV.getDataRange().getValues();
// Fila 0: headers — cols J-O (idx 9-14) = VN por clase
// Cols P-U (idx 15-20) = capital remanente calculado
var CLASES = ['Clase 13','Clase 17','Clase 18','Clase 19','Clase 20','Clase 21'];
var VN_COLS = [9,10,11,12,13,14]; // J,K,L,M,N,O = VN
var CAP_COLS = [15,16,17,18,19,20]; // P,Q,R,S,T,U = capital remanente
// V23 P5: Clase 19 = Badlar Privada 40,50% + Spread 6,99% = 47,49% TNA
// V23 P14.8: tasas oficiales del prospecto actualizadas
// Clase 13 (CVSA 54497) → 10%
// Clase 17 (CVSA 56340) → 9,5%
// Clase 18 (CVSA 57761) → 9,25%
// Clase 19 (CVSA 57760) → 47,49%
// Clase 20 (CVSA 57933) → 8%
// Clase 21 (CVSA 57934) → 7%
var claseATasa = {'Clase 13':10,'Clase 17':9.5,'Clase 18':9.25,'Clase 19':47.49,'Clase 20':8,'Clase 21':7};
var claseATC = {'Clase 13':1485,'Clase 17':1205,'Clase 18':1485,'Clase 19':1,'Clase 20':1485,'Clase 21':1205};
var claseAPago = {'Clase 13':'USD','Clase 17':'DL','Clase 18':'USD','Clase 19':'ARS','Clase 20':'USD','Clase 21':'DL'};
// Buscar fila del acreedor
var filaAcreedor = null;
for (var i = 1; i < datos.length; i++) {
var nlegFila = String(datos[i][0]||'').trim().toUpperCase();
var cuitFila = String(datos[i][2]||'').replace(/[-\s]/g,'').trim();
var nlegBuscarNum = nlegBuscar.replace(/ON$/,'');
var nlegFilaNum = nlegFila.replace(/ON$/,'');
var matchNleg = nlegBuscar && (nlegFila === nlegBuscar || nlegFilaNum === nlegBuscarNum);
var matchCuit = cuitBuscar && cuitFila && cuitFila === cuitBuscar;
if (matchNleg || matchCuit) { filaAcreedor = datos[i]; break; }
}
if (!filaAcreedor) return resp({ encontrado: false, nleg: nlegBuscar, error: 'Legajo no encontrado en Verificado' });
var tenencias = {}, detalle = {};
var cuitReal = String(filaAcreedor[2]||'').replace(/[-\s]/g,'');
var acreedor = String(filaAcreedor[1]||'');
CLASES.forEach(function(clase, i) {
var vn = parseFloat(filaAcreedor[VN_COLS[i]]) || 0;
var cap = parseFloat(filaAcreedor[CAP_COLS[i]]) || 0;
if (vn <= 0 && cap <= 0) return;
var remPct = vn > 0 ? cap / vn : 0;
tenencias[clase] = vn;
detalle[clase] = { vn: vn, capital_remanente: cap, remanente_pct: remPct,
tasa: claseATasa[clase]||0, tc: claseATC[clase]||1, pago: claseAPago[clase]||'USD' };
});
return resp({ encontrado: true, nleg: nlegBuscar, cuit: cuitReal, acreedor: acreedor, tenencias: tenencias, detalle: detalle });
} catch(ex) {
return resp({ error: 'Error leyendo Verificado: ' + ex.message });
}
}
// ── Ping de diagnóstico ──
if (usuario === 'ping') {
const sheets = ss.getSheets().map(function(s){ return s.getName(); });
var rootOk = false;
try { DriveApp.getFolderById(ROOT_FOLDER_ID); rootOk = true; } catch(ex) {}
return resp({ ok: true, sheets: sheets, sheetUsers: SHEET_USERS, rootFolderOk: rootOk, rootFolderId: ROOT_FOLDER_ID });
}
// ── Importar solapa individual ──
if (usuario && usuario !== 'todos') {
const tab = ss.getSheetByName(usuario);
if (!tab) return resp({ error: 'Solapa no encontrada: "' + usuario + '". Disponibles: ' + ss.getSheets().map(function(s){return s.getName();}).join(', ') });
return resp({ usuario: usuario, acreedores: getRows(tab) });
}
// ── Importar todos ──
const result = {};
SHEET_USERS.forEach(function(u) {
const tab = ss.getSheetByName(u);
if (tab) result[u] = getRows(tab);
});
return resp({ todos: true, data: result });
}
// Busca en ROOT_FOLDER_ID una subcarpeta cuyo nombre empiece con "nleg -"
// También acepta coincidencia parcial con el nombre del acreedor
function buscarCarpetaLegajo(nleg, acreedor, folderId) {
folderId = folderId || ROOT_FOLDER_ID;
try {
var rootFolder = DriveApp.getFolderById(folderId);
} catch(ex) {
return { error: 'No se pudo acceder a la carpeta raíz (ID: ' + folderId + '). Verificar en ⚙ Configuración. Detalle: ' + ex.message };
}
// Buscar por número de legajo exacto al inicio del nombre: "595 -"
var prefijo = nleg + ' -';
var query = 'mimeType = "application/vnd.google-apps.folder" and title contains "' + nleg + '"';
var it = rootFolder.searchFolders(query);
var candidatos = [];
while (it.hasNext()) {
var f = it.next();
var nombre = f.getName();
// El nombre debe empezar con el número de legajo (para evitar falsos positivos)
if (nombre.indexOf(prefijo) === 0 || nombre.indexOf(nleg + '-') === 0) {
candidatos.push({ nombre: nombre, url: f.getUrl(), id: f.getId() });
}
}
if (candidatos.length === 0) {
// Segundo intento: buscar más flexible (sin guión)
var it2 = rootFolder.getFolders();
while (it2.hasNext()) {
var f2 = it2.next();
var n2 = f2.getName();
if (n2.indexOf(nleg) === 0) {
candidatos.push({ nombre: n2, url: f2.getUrl(), id: f2.getId() });
}
}
}
if (candidatos.length === 0) {
return { encontrado: false, nleg: nleg, mensaje: 'No se encontró carpeta para el legajo ' + nleg };
}
// Si hay más de uno, preferir el que también coincida con el nombre del acreedor
var mejor = candidatos[0];
if (acreedor && candidatos.length > 1) {
var acrUpper = acreedor.toUpperCase();
candidatos.forEach(function(c) {
if (c.nombre.toUpperCase().indexOf(acrUpper.slice(0,6)) !== -1) mejor = c;
});
}
return { encontrado: true, nleg: nleg, nombre: mejor.nombre, url: mejor.url, id: mejor.id, candidatos: candidatos };
}
function getRows(tab) {
const data = tab.getDataRange().getValues();
if (data.length < 2) return [];
const headers = data[0].map(function(h) { return String(h).trim(); });
return data.slice(1)
.filter(function(row) { return row[0] !== '' && row[0] !== null && row[0] !== undefined; })
.map(function(row) {
var obj = {};
headers.forEach(function(h, i) {
obj[h] = (row[i] !== null && row[i] !== undefined) ? String(row[i]) : '';
});
return obj;
});
}
function resp(data) {
return ContentService
.createTextOutput(JSON.stringify(data))
.setMimeType(ContentService.MimeType.JSON);
}
function testExport() {
SHEET_USERS.forEach(function(u) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var tab = ss.getSheetByName(u);
if (tab) {
var rows = getRows(tab);
Logger.log(u + ': ' + rows.length + ' filas');
if (rows[0]) Logger.log('Headers: ' + Object.keys(rows[0]).join(' | '));
} else {
Logger.log('NO ENCONTRADA: ' + u);
}
});
}
// Probar búsqueda de carpeta manualmente
function testBuscarCarpeta() {
Logger.log(JSON.stringify(buscarCarpetaLegajo('595', 'SUMINOX SRL', ROOT_FOLDER_ID)));
}
👥 Operadores del equipo
Gestión de usuarios del sistema. Cada operador tiene su propio email y contraseña. Todos pueden editar a los demás. El operador activo se muestra arriba a la derecha.
Cargando operadores…
Editar operador
Varios operadores pueden compartir la misma cartera (ej: un colaborador de Marce usa cartera "Marce" y loguea con su propio usuario — queda trazabilidad de quién editó qué).
⚡ URL Directa del Apps Script (opcional — evita timeout del proxy para importar ON)
Si la importación de tenencias ON falla por timeout, pegá acá la URL directa del deployment del Apps Script. La encontrás en script.google.com → Implementar → Administrar → Copiar URL
✉ Gmail — Cuenta de Verificaciones
Cada operadora configura su propio acceso a verificaciones@concursocelulosa.com.ar (cuenta delegada desde su Gmail personal).
Usuario actual: —
Sin configurar — usá el wizard de abajo para setup en 30 segundos.
👥 Ver config de todas las operadoras
🧙 Wizard — Configurar acceso a Gmail
Paso 1 · Abrí Gmail
Hacé clic en el botón de abajo → se abre una pestaña nueva con Gmail. Si no estás logueada, iniciá sesión con tu cuenta personal. Si ya tenés Gmail abierto con tu cuenta, ignorá el botón y seguí al paso 2.
Paso 2 · Cambiá a verificaciones@
Dentro de Gmail, clic en el avatar circular arriba a la derecha → seleccioná verificaciones@concursocelulosa.com.ar.
Si no la ves en la lista, pedí a la síndica que te dé permiso de delegación de esa cuenta.
Paso 3 · Copiame la URL
Ya estando en la bandeja de verificaciones@, copiá la URL completa que aparece en la barra de direcciones del navegador y pegala abajo:
📊 Tasa Activa BNA Cartera General
Tabla de valores TNA mensuales usada en el cálculo automático de intereses (ON vencidas tramo 2, facturas/cheques con checkbox BNA tildado).
💾 Datos
🧹 Borrar solo contenido: limpia los informes cargados (opiniones, causas, facturas, cheques, ON, observaciones) pero mantiene los acreedores asignados y sus datos de identificación (nombre, CUIT, legajo, email, domicilios). 🗑 Borrar todo: elimina también los acreedores. Acción irreversible.
Los datos se guardan localmente en este navegador (localStorage). Exportá un JSON para respaldo o para transferir entre computadoras.
+ Nuevo Acreedor
Identificación del Expediente
Montos solicitados
Estado del Expediente
Documentación del Expediente
Carpeta y PDF en Drive
Asignar a Operador
☁ Configuración — Google Drive
¿Cómo funciona?
Apps Script
Mi URL
La app genera el PDF en tu navegador y lo envía al Apps Script que instalás una sola vez, que lo guarda en Drive.
Abrí script.google.com
Nuevo proyecto → pegá el código de Apps Script
Cambiá FOLDER_ID por el ID de tu carpeta
Implementar → Aplicación web → Ejecutar como: Yo · Acceso: Cualquier persona