Desde que agencias Shalom sale tu mercaderia. Marca una como default.
Conectar Google Sheets
Sube pedidos desde tu Sheets a TrackPro con un solo clic
Configuración — solo una vez
1
Abre tu Google Sheets
Ve a Extensiones → Apps Script en el menú superior
2
Pega el código
Borra todo lo que haya, copia el código de abajo y pégalo (Ctrl+V)
3
Escribe tu contraseña
Busca la línea que dice [ESCRIBE AQUI TU CONTRASEÑA DE TRACKPRO] y reemplázala por tu contraseña de TrackPro
4
Guarda y ejecuta
Clic en Guardar () → selecciona la función onOpen → clic en ▶ Ejecutar → Autorizar permisos
✓
¡Listo! Recarga tu Sheets
Aparecerá el menú TrackPro arriba. Desde ahí subes todos los pedidos de un clic
Tus datos — ya incluidos en el código
Empresa ID
—
Email
—
Contraseña: debes escribirla manualmente en el código — busca la línea [ESCRIBE AQUI TU CONTRASEÑA DE TRACKPRO]
Código Apps Script
// =============================================
// TRACKPRO — Script para Google Apps Script
// 1) Recibe pedidos de TrackPro → Sheet (doGet)
// 2) Sube pedidos de Sheet → TrackPro
// =============================================
var EMPRESA_ID = 'TU_EMPRESA_ID';
var FIREBASE_EMAIL = 'TU_EMAIL';
var FIREBASE_PASSWORD = 'TU_PASSWORD';
var FIREBASE_PROJECT = 'empresas-25fc2';
var FIREBASE_API_KEY = 'AIzaSyDLTy_Gp83DPFqelvSA_PgnOHooQY1H4jI';
// ════════════════════════════════════════════
// SUBIR TODO EL SHEET → TRACKPRO
// ════════════════════════════════════════════
function subirATrackPro() {
var sheet = SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getValues();
if (data.length < 2) {
SpreadsheetApp.getUi().alert('La hoja esta vacia.');
return;
}
var primeraFila = data[0].map(function(h){ return String(h||'').toLowerCase(); });
var esTabla = primeraFila.some(function(h){
return h.indexOf('nombre') !== -1 || h.indexOf('dni') !== -1;
});
var pedidos = esTabla ? parsearTabla(data) : parsearFormato(data);
if (pedidos.length === 0) {
SpreadsheetApp.getUi().alert('No se encontraron pedidos validos con DNI.');
return;
}
var ui = SpreadsheetApp.getUi();
var resp = ui.alert('TrackPro', 'Se van a subir ' + pedidos.length + ' pedidos. Continuar?', ui.ButtonSet.YES_NO);
if (resp !== ui.Button.YES) return;
var token;
try { token = getFirebaseToken(); }
catch(e) { ui.alert('Error de login: ' + e.message); return; }
subirFirestore(pedidos, sheet, 2, token);
}
// ════════════════════════════════════════════
// SUBIR SELECCIÓN → TRACKPRO
// ════════════════════════════════════════════
function subirSeleccionATrackPro() {
var sheet = SpreadsheetApp.getActiveSheet();
var sel = sheet.getActiveRange();
var data = sel.getValues();
if (!data || data.length === 0) {
SpreadsheetApp.getUi().alert('No hay celdas seleccionadas.');
return;
}
var primeraFila = data[0].map(function(h){ return String(h||'').toLowerCase(); });
var esTabla = primeraFila.some(function(h){
return h.indexOf('nombre') !== -1 || h.indexOf('dni') !== -1;
});
if (!esTabla) {
var filaInicio = sel.getRow();
if (filaInicio > 1) {
var headersRow = sheet.getRange(filaInicio - 1, sel.getColumn(), 1, sel.getNumColumns()).getValues()[0];
var headersLow = headersRow.map(function(h){ return String(h||'').toLowerCase(); });
if (headersLow.some(function(h){ return h.indexOf('nombre') !== -1 || h.indexOf('dni') !== -1; })) {
data.unshift(headersRow);
esTabla = true;
}
}
}
var pedidos = esTabla ? parsearTabla(data) : parsearFormato(data);
if (pedidos.length === 0) {
SpreadsheetApp.getUi().alert('No se encontraron pedidos validos en la seleccion.');
return;
}
var ui = SpreadsheetApp.getUi();
var resp = ui.alert('TrackPro', 'Se van a subir ' + pedidos.length + ' pedidos de la seleccion. Continuar?', ui.ButtonSet.YES_NO);
if (resp !== ui.Button.YES) return;
var token;
try { token = getFirebaseToken(); }
catch(e) { ui.alert('Error de login: ' + e.message); return; }
subirFirestore(pedidos, sheet, sel.getRow(), token);
}
// ════════════════════════════════════════════
// AUTH FIREBASE
// ════════════════════════════════════════════
function getFirebaseToken() {
var url = 'https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=' + FIREBASE_API_KEY;
var payload = JSON.stringify({ email: FIREBASE_EMAIL, password: FIREBASE_PASSWORD, returnSecureToken: true });
var resp = UrlFetchApp.fetch(url, { method: 'post', contentType: 'application/json', payload: payload, muteHttpExceptions: true });
var data = JSON.parse(resp.getContentText());
if (!data.idToken) throw new Error('Login fallido: ' + (data.error ? data.error.message : 'sin token'));
return data.idToken;
}
// ════════════════════════════════════════════
// PARSERS
// ════════════════════════════════════════════
function buscarColumna(headers, palabras) {
for (var k = 0; k < palabras.length; k++)
for (var i = 0; i < headers.length; i++)
if (headers[i].indexOf(palabras[k]) !== -1) return i;
return -1;
}
function parsearTabla(data) {
var headers = data[0].map(function(h){ return String(h||'').toLowerCase().trim(); });
var cN = buscarColumna(headers, ['nombre','cliente','destinatario']);
var cD = buscarColumna(headers, ['dni','documento']);
var cT = buscarColumna(headers, ['celular','telefono','tel']);
var cP = buscarColumna(headers, ['producto','pedido','items']);
var cM = buscarColumna(headers, ['monto','total','precio','valor']);
var cPr = buscarColumna(headers, ['provincia','region','departamento']);
var cCi = buscarColumna(headers, ['ciudad','distrito']);
var cDi = buscarColumna(headers, ['direccion','address']);
var cO = buscarColumna(headers, ['obs','nota','observ']);
var pedidos = [];
for (var r = 1; r < data.length; r++) {
var row = data[r];
var nom = cN >= 0 ? String(row[cN]||'').trim() : '';
var dni = cD >= 0 ? String(row[cD]||'').replace(/[^0-9]/g,'') : '';
if (!nom || dni.length < 7) continue;
var prods = [];
if (cP >= 0 && row[cP]) {
var pa = String(row[cP]).split(/[,\n|]/);
for (var pp = 0; pp < pa.length; pp++) {
var pt = pa[pp].trim();
if (pt) prods.push(pt);
}
}
var monto = 0;
if (cM >= 0) monto = parseFloat(String(row[cM]||'0').replace(/[^0-9.]/g,'')) || 0;
pedidos.push({
nombre: nom, dni: dni,
telefono: cT >= 0 ? String(row[cT]||'').replace(/[^0-9]/g,'') : '',
productos: prods, monto: monto,
provincia: cPr >= 0 ? String(row[cPr]||'').trim() : '',
ciudad: cCi >= 0 ? String(row[cCi]||'').trim() : '',
direccion: cDi >= 0 ? String(row[cDi]||'').trim() : '',
observaciones: cO >= 0 ? String(row[cO]||'').trim() : '',
estado: 'pendiente'
});
}
return pedidos;
}
function parsearFormato(data) {
var numCols = data[0] ? data[0].length : 2;
var pedidos = [];
var vistos = {};
for (var colL = 0; colL < numCols - 1; colL++) {
var colV = colL + 1;
if (colV >= numCols) continue;
var enc = parsearBloque(data, colL, colV);
for (var fi = 0; fi < enc.length; fi++) {
var p = enc[fi];
var cl = p.dni + '|' + p.nombre;
if (p.dni && p.nombre && !vistos[cl]) {
vistos[cl] = true;
pedidos.push(p);
}
}
}
return pedidos;
}
function parsearBloque(data, colL, colV) {
var result = [];
var curr = null;
var espDest = false;
for (var fi = 0; fi < data.length; fi++) {
var label = String(data[fi][colL]||'').trim();
var value = String(data[fi][colV]||'').trim();
var ll = label.toLowerCase();
if (ll.indexOf('pedido') === 0) {
if (curr && curr.dni) result.push(curr);
curr = { nombre:'', dni:'', telefono:'', provincia:'', ciudad:'', direccion:'', productos:[], monto:0, estado:'pendiente', observaciones:'' };
espDest = false;
if (value) {
var lp = value.split('\n');
for (var l = 0; l < lp.length; l++) {
var ln = lp[l].replace(/^[\u2714\u2713\-\u2022 ]+/, '').trim();
if (ln && !/^(pedido|datos|celular|destino|valor|total|estado)/i.test(ln)) curr.productos.push(ln);
}
}
continue;
}
if (!curr) continue;
if (ll.indexOf('datos del dest') !== -1 && value) {
espDest = false;
var ld = value.split('\n');
for (var l2 = 0; l2 < ld.length; l2++) {
var ln2 = ld[l2];
var md = ln2.match(/dni\s*[:\-]?\s*(\d{7,8})/i);
if (md) curr.dni = md[1];
var mn = ln2.match(/nombres?\s*[:\-]\s*(.+)/i);
if (mn) curr.nombre = mn[1].trim();
var ma = ln2.match(/apellidos?\s*[:\-]\s*(.+)/i);
if (ma && curr.nombre) curr.nombre += ' ' + ma[1].trim();
}
continue;
}
if (/^celular|^tel/i.test(label) && value) { curr.telefono = value.replace(/[^0-9]/g,''); continue; }
if (/^destino/i.test(label)) {
espDest = true;
if (value && !/^agencia$/i.test(value) && value.indexOf('/') !== -1) {
var pt = value.split('/');
curr.provincia = pt[0].trim();
curr.ciudad = pt[pt.length-1].trim();
espDest = false;
}
continue;
}
if (espDest && !label && value) {
espDest = false;
var ldes = value.split('\n');
for (var l3 = 0; l3 < ldes.length; l3++) {
var ln3 = ldes[l3].trim();
if (ln3.indexOf('/') !== -1 && !/shalom/i.test(ln3)) {
var pts = ln3.split('/');
if (pts.length >= 2) { curr.provincia = pts[0].trim(); curr.ciudad = pts[pts.length-1].trim(); }
} else if (ln3 && !/shalom|agencia/i.test(ln3) && !curr.direccion) {
curr.direccion = ln3;
}
}
continue;
}
if (/^valor del prod|^monto|^total/i.test(label) && value) {
var n = parseFloat(value.replace(/[^0-9.]/g,''));
if (n > 0 && curr.monto === 0) curr.monto = n;
continue;
}
if (/^obs/i.test(label) && value) curr.observaciones = value;
}
if (curr && curr.dni) result.push(curr);
return result;
}
// ════════════════════════════════════════════
// SUBIR A FIRESTORE
// ════════════════════════════════════════════
function subirFirestore(pedidos, sheet, filaInicio, token) {
var base = 'https://firestore.googleapis.com/v1/projects/' + FIREBASE_PROJECT + '/databases/(default)/documents/empresas/' + EMPRESA_ID + '/pedidos';
var subidos = 0;
var errores = [];
for (var i = 0; i < pedidos.length; i++) {
var p = pedidos[i];
var vals = [];
for (var vi = 0; vi < p.productos.length; vi++) vals.push({ stringValue: p.productos[vi] });
var docData = {
fields: {
nombre: { stringValue: p.nombre },
dni: { stringValue: p.dni },
telefono: { stringValue: p.telefono },
productos: { arrayValue: { values: vals } },
monto: { doubleValue: p.monto },
provincia: { stringValue: p.provincia },
ciudad: { stringValue: p.ciudad },
direccion: { stringValue: p.direccion },
observaciones: { stringValue: p.observaciones },
estado: { stringValue: p.estado },
tracking: { stringValue: '' },
creadoEn: { timestampValue: new Date().toISOString() },
updatedAt: { timestampValue: new Date().toISOString() }
}
};
try {
var r = UrlFetchApp.fetch(base, {
method: 'post',
contentType: 'application/json',
headers: { 'Authorization': 'Bearer ' + token },
payload: JSON.stringify(docData),
muteHttpExceptions: true
});
var c = r.getResponseCode();
if (c === 200 || c === 201) {
subidos++;
} else {
errores.push('Fila ' + (filaInicio + i) + ': HTTP ' + c);
}
} catch(e) {
errores.push('Fila ' + (filaInicio + i) + ': ' + e.message);
}
if (i > 0 && i % 10 === 0) Utilities.sleep(300);
}
var msg = subidos + ' pedidos subidos a TrackPro.';
if (errores.length) msg += '\n\nErrores (' + errores.length + '):\n' + errores.slice(0,5).join('\n');
SpreadsheetApp.getUi().alert('TrackPro', msg, SpreadsheetApp.getUi().ButtonSet.OK);
}
// ════════════════════════════════════════════
// EXPORTAR (Apps Script como Web App)
// ════════════════════════════════════════════
function doGet(e) {
try {
if (!e.parameter || !e.parameter.data) {
return ContentService.createTextOutput(JSON.stringify({ status: 'TrackPro activo' })).setMimeType(ContentService.MimeType.JSON);
}
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Pedidos') || ss.getActiveSheet();
var data = JSON.parse(e.parameter.data);
var esNuevo = sheet.getLastRow() === 0;
if (esNuevo) {
sheet.setName('Pedidos');
var headers = ['FECHA','F. ENVIO','#','NOMBRE','DNI','TEL','ENVIO','DESTINO','PRODUCTOS','VENTA S/','COSTO PROD','COSTO ENV','COBRO ENV','SUBSIDIO','GANANCIA S/','N SHALOM','COD','CLAVE','OBS','VENDEDOR'];
sheet.appendRow(headers);
var hRange = sheet.getRange(1,1,1,headers.length);
hRange.setFontWeight('bold').setFontSize(9).setWrap(true).setVerticalAlignment('middle');
sheet.getRange(1,1,1,2).setBackground('#0d47a1').setFontColor('#fff');
sheet.getRange(1,3,1,4).setBackground('#1565c0').setFontColor('#fff');
sheet.getRange(1,7,1,2).setBackground('#2e7d32').setFontColor('#fff');
sheet.getRange(1,9,1,1).setBackground('#6a1b9a').setFontColor('#fff');
sheet.getRange(1,10,1,5).setBackground('#e65100').setFontColor('#fff');
sheet.getRange(1,15,1,1).setBackground('#1b5e20').setFontColor('#fff');
sheet.getRange(1,16,1,3).setBackground('#00838f').setFontColor('#fff');
sheet.getRange(1,19,1,1).setBackground('#37474f').setFontColor('#fff');
sheet.getRange(1,20,1,1).setBackground('#880e4f').setFontColor('#fff');
sheet.setFrozenRows(1);
sheet.setColumnWidths(1,1,80);sheet.setColumnWidths(2,1,80);sheet.setColumnWidths(3,1,50);
sheet.setColumnWidths(4,1,150);sheet.setColumnWidths(5,1,80);sheet.setColumnWidths(6,1,85);
sheet.setColumnWidths(7,1,65);sheet.setColumnWidths(8,1,110);sheet.setColumnWidths(9,1,175);
sheet.setColumnWidths(10,1,70);sheet.setColumnWidths(11,1,75);sheet.setColumnWidths(12,1,70);
sheet.setColumnWidths(13,1,70);sheet.setColumnWidths(14,1,65);sheet.setColumnWidths(15,1,80);
sheet.setColumnWidths(16,1,80);sheet.setColumnWidths(17,1,45);sheet.setColumnWidths(18,1,45);
sheet.setColumnWidths(19,1,140);sheet.setColumnWidths(20,1,90);
if (!sheet.getFilter()) sheet.getRange(1,1,1,headers.length).createFilter();
var rs = ss.getSheetByName('Resumen Vendedores');
if (!rs) {
rs = ss.insertSheet('Resumen Vendedores');
rs.getRange('A1').setValue('VENDEDOR').setFontWeight('bold').setBackground('#880e4f').setFontColor('#fff');
rs.getRange('B1').setValue('PEDIDOS').setFontWeight('bold').setBackground('#880e4f').setFontColor('#fff');
rs.getRange('C1').setValue('VENTA TOTAL').setFontWeight('bold').setBackground('#e65100').setFontColor('#fff');
rs.getRange('D1').setValue('COSTO TOTAL').setFontWeight('bold').setBackground('#e65100').setFontColor('#fff');
rs.getRange('E1').setValue('GANANCIA TOTAL').setFontWeight('bold').setBackground('#2e7d32').setFontColor('#fff');
rs.getRange('A2').setFormula('=IFERROR(SORT(UNIQUE(FILTER(Pedidos!T2:T,Pedidos!T2:T<>"")),1,TRUE),"")');
rs.getRange('B2').setFormula('=IFERROR(ARRAYFORMULA(IF(A2:A<>"",COUNTIF(Pedidos!T:T,A2:A),"")),0)');
rs.getRange('C2').setFormula('=IFERROR(ARRAYFORMULA(IF(A2:A<>"",SUMIF(Pedidos!T:T,A2:A,Pedidos!J:J),"")),0)');
rs.getRange('D2').setFormula('=IFERROR(ARRAYFORMULA(IF(A2:A<>"",SUMIF(Pedidos!T:T,A2:A,Pedidos!K:K),"")),0)');
rs.getRange('E2').setFormula('=IFERROR(ARRAYFORMULA(IF(A2:A<>"",SUMIF(Pedidos!T:T,A2:A,Pedidos!O:O),"")),0)');
rs.setColumnWidth(1,120);rs.setColumnWidth(2,80);rs.setColumnWidths(3,3,100);
rs.setFrozenRows(1);
rs.getRange('C:E').setNumberFormat('#,##0.00');
}
}
var buildRow = function(p) {
return [
p.fecha||'',p.fechaEnvio||'',p.num||'',p.nombre||'',p.dni||'',p.telefono||'',
p.tipoEnvio||'',p.provincia||'',p.productos||'',
p.monto||0,p.costoProductos||0,p.costoEnvio||0,p.cobroEnvio||0,p.subsidio||0,p.gananciaNeta||0,
p.numeroShalom||'',p.codigoShalom||'',p.claveShalom||'',p.observaciones||'',p.vendedor||''
];
};
if (Array.isArray(data)) {
for (var i = 0; i < data.length; i++) sheet.appendRow(buildRow(data[i]));
} else {
sheet.appendRow(buildRow(data));
}
var lr = sheet.getLastRow();
if (lr > 1) {
sheet.getRange(lr,1,1,20).setFontSize(9).setVerticalAlignment('middle');
sheet.getRange(lr,10,1,6).setNumberFormat('#,##0.00');
}
return ContentService.createTextOutput(JSON.stringify({ok:true})).setMimeType(ContentService.MimeType.JSON);
} catch(err) {
return ContentService.createTextOutput(JSON.stringify({ok:false,error:err.toString()})).setMimeType(ContentService.MimeType.JSON);
}
}
// ════════════════════════════════════════════
// SYNC DIARIO AUTOMATICO (3AM) — Lee Firestore directo
// ════════════════════════════════════════════
function sincronizarDiario() {
var token = getFirebaseToken();
var url = 'https://firestore.googleapis.com/v1/projects/' + FIREBASE_PROJECT + '/databases/(default)/documents/empresas/' + EMPRESA_ID + '/pedidos?pageSize=500';
var pedidos = [];
var nextToken = '';
while (true) {
var fetchUrl = url + (nextToken ? '&pageToken=' + nextToken : '');
var resp = UrlFetchApp.fetch(fetchUrl, { headers: { 'Authorization': 'Bearer ' + token }, muteHttpExceptions: true });
var body = JSON.parse(resp.getContentText());
if (!body.documents) break;
for (var i = 0; i < body.documents.length; i++) {
var d = body.documents[i];
var f = d.fields || {};
var v = function(k) { return f[k] ? (f[k].stringValue || f[k].integerValue || f[k].doubleValue || '') : ''; };
var n = function(k) { return f[k] ? parseFloat(f[k].doubleValue || f[k].integerValue || '0') : 0; };
var ts = f.creadoEn ? (f.creadoEn.timestampValue || '') : '';
var fecha = ts ? new Date(ts).toLocaleDateString('es-PE') : '';
var prods = '';
if (f.productos && f.productos.arrayValue && f.productos.arrayValue.values) {
prods = f.productos.arrayValue.values.map(function(x){ return x.stringValue||''; }).join(' | ');
}
var eq = {};
pedidos.push([
fecha, v('fechaEnvio'), '', v('nombre'), v('dni'), v('telefono'),
v('tipoEnvio')=='domicilio'?'Domicilio':'Agencia', v('provincia'), prods,
n('totalVenta')||n('monto'), n('totalCosto'), n('costoEnvio'), n('cobroEnvio'),
Math.max(0,n('costoEnvio')-n('cobroEnvio')), n('gananciaNeta'),
v('numeroShalom'), v('codigoShalom'), v('claveShalom'), v('observaciones'), v('creadoPorEmail')
]);
}
nextToken = body.nextPageToken || '';
if (!nextToken) break;
}
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Pedidos') || ss.getActiveSheet();
sheet.clearContents();
var headers = ['FECHA','F. ENVIO','#','NOMBRE','DNI','TEL','ENVIO','DESTINO','PRODUCTOS','VENTA S/','COSTO PROD','COSTO ENV','COBRO ENV','SUBSIDIO','GANANCIA S/','N SHALOM','COD','CLAVE','OBS','VENDEDOR'];
sheet.appendRow(headers);
var hRange = sheet.getRange(1,1,1,headers.length);
hRange.setFontWeight('bold').setFontSize(9).setWrap(true).setVerticalAlignment('middle');
sheet.getRange(1,1,1,2).setBackground('#0d47a1').setFontColor('#fff');
sheet.getRange(1,3,1,4).setBackground('#1565c0').setFontColor('#fff');
sheet.getRange(1,7,1,2).setBackground('#2e7d32').setFontColor('#fff');
sheet.getRange(1,9,1,1).setBackground('#6a1b9a').setFontColor('#fff');
sheet.getRange(1,10,1,5).setBackground('#e65100').setFontColor('#fff');
sheet.getRange(1,15,1,1).setBackground('#1b5e20').setFontColor('#fff');
sheet.getRange(1,16,1,3).setBackground('#00838f').setFontColor('#fff');
sheet.getRange(1,19,1,1).setBackground('#37474f').setFontColor('#fff');
sheet.getRange(1,20,1,1).setBackground('#880e4f').setFontColor('#fff');
sheet.setFrozenRows(1);
for (var j = 0; j < pedidos.length; j++) {
sheet.appendRow(pedidos[j]);
}
if (pedidos.length > 0) {
sheet.getRange(2,10,pedidos.length,6).setNumberFormat('#,##0.00');
sheet.getRange(2,1,pedidos.length,20).setFontSize(9);
}
if (!sheet.getFilter()) sheet.getRange(1,1,1,headers.length).createFilter();
}
function crearTrigger3AM() {
var triggers = ScriptApp.getProjectTriggers();
for (var i = 0; i < triggers.length; i++) {
if (triggers[i].getHandlerFunction() === 'sincronizarDiario') {
ScriptApp.deleteTrigger(triggers[i]);
}
}
ScriptApp.newTrigger('sincronizarDiario')
.timeBased()
.atHour(3)
.everyDays(1)
.inTimezone('America/Lima')
.create();
}
// ════════════════════════════════════════════
// MENU
// ════════════════════════════════════════════
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('TrackPro')
.addItem('Subir TODO el sheet a TrackPro', 'subirATrackPro')
.addItem('Subir SELECCION a TrackPro', 'subirSeleccionATrackPro')
.addSeparator()
.addItem('Sincronizar AHORA desde TrackPro', 'sincronizarDiario')
.addItem('Activar sync diario 3AM', 'crearTrigger3AM')
.addSeparator()
.addItem('Limpiar hoja', 'limpiarHoja')
.addToUi();
}
function limpiarHoja() {
var ui = SpreadsheetApp.getUi();
if (ui.alert('Borrar todos los datos?',ui.ButtonSet.YES_NO) === ui.Button.YES) {
SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().clear();
}
}
El botón copia el código y abre tu Sheets. Desde ahí ve a
Extensiones → Apps Script, borra lo que haya,
pega con Ctrl+V y escribe tu contraseña donde dice
[ESCRIBE AQUI TU CONTRASEÑA DE TRACKPRO].
EXPORTAR PEDIDOS A TU SHEETS
Pega la URL de tu Apps Script para exportar pedidos de TrackPro a Google Sheets.
🎨
Editor de Ticket
Personaliza el voucher que se genera para tus clientes
Plantilla
Color principal
Tu color de marca
Textos
🎉 Sello promoción
🎟️ Bloque de cupón
Campos visibles
🔌
API & Integraciones
Conecta tu sistema a Zapier, Make, n8n, Google Sheets, o cualquier app externa via REST API
Sin generar
⚠️ La API key da acceso completo a tus pedidos e inventario. No la compartas en publico (solo en backends seguros).
Configura las APIs de courier para rastreo en tiempo real
Shalom PerúACTIVO
Credenciales para crear pre-guías automáticas en Shalom Pro
API personalizadaOPCIONAL
API guardada correctamente
Plantillas WhatsApp
Mensajes automáticos al contactar clientes desde la tabla de pedidos
Variables disponibles: {nombre} — Nombre del cliente {dni} — DNI {pedidoId} — ID del pedido {monto} — Monto (S/) {destino} — Provincia/destino {direccion} — Dirección o sede {numeroShalom} — N° orden Shalom {codigoShalom} — Código Shalom {claveShalom} — 🔑 Clave de acceso Shalom {medioPago} — 💳 Medio de pago acordado {tracking} — Link de tracking {gps} — Link de Google Maps con la dirección {estado} — Estado del pedido
Las plantillas se guardan en la configuración de tu empresa
📋
Plantilla Copiar Rápido
Mensaje que se copia al portapapeles desde el botón 📋 en la tabla de pedidos
Mismas variables que WhatsApp:{nombre}{dni}{pedidoId}{monto}{destino}{direccion}{numeroShalom}{codigoShalom}{claveShalom}{medioPago}{tracking}{gps}{estado}{productos}
💳
Medios de pago
Cómo pueden pagar tus clientes. Aparecen en el formulario de nuevo pedido.
📋 CRM
En vivo
Clientes · 0
🔍
👤
Seleccioná un cliente de la lista para ver su historial
Personas que dejaron sus datos pero aún no confirmaron el pago.
📭
No hay pedidos sin confirmar
📦 Inventario
📦
No hay productos cargados. Agregá tu primer producto con el botón de arriba.
🤖
Importar Inventario con IA
Lectura inteligente de Excel · agrupa productos y variantes automáticamente
📊
Arrastra tu Excel acá o hacé click
Acepta .xlsx, .xls, .csv — la IA detecta columnas automáticamente
💡 Cómo funciona: Subís tu Excel (cualquier formato — productos por fila, variantes mezcladas, etc).
La IA lo analiza, agrupa por producto, detecta variantes/precios/stock/SKU, y te muestra un preview antes de guardar nada.
Leyendo archivo...
Esto puede tomar 5-15 segundos
— productos detectados
—
😕
Algo salió mal
—
📦
Nuevo producto
Total: 0
💡 Este es el precio base. Después puedes agregar variantes (sabores, tamaños) con precios diferentes.
Nueva variante
Total: 0
Registro de ventas
N° Pedido
Fecha
Cliente
DNI
Productos
Monto (S/)
Estado
Destino
📋
No hay ventas para mostrar con los filtros aplicados.
Rastreo y Búsqueda
🔍 Buscar pedidos por DNI
Ingresa el DNI del cliente para ver todos sus pedidos registrados
🚚 Rastreo Shalom
Ingresa el número de orden de Shalom Perú para ver el estado del envío en tiempo real
Consultando Shalom...
Pagos y Costos
Fecha
Cliente
Destino
Costo Envío
Cobro Envío
Subsidio
📦
No hay envíos con costo en este rango de fechas.
Seleccioná un rango de fechas arriba.
TOTAL PAGOSS/ 0.00
💸
No hay pagos registrados.
hasta
🧾 TOTAL GASTOSS/ 0.00
🧾
No hay gastos registrados.
🧾 Registrar Gasto
Click para subir foto del comprobante
💰 Registrar Pago
📷 Click para subir comprobante
Empresas registradas
Empresa
Plan
Pedidos
Usuarios
Estado
Registro
Acciones
🏢
No hay empresas registradas aún
Todos los usuarios
Nombre
Email
Empresa
Rol
Acciones
NUEVA EMPRESA
Gratis
S/ 0/mes
50 pedidos
Básico
S/ 49/mes
500 pedidos
Pro
S/ 99/mes
Ilimitado
Nuevo Pedido
Autoguardado
Datos del cliente
Envío y destino
📤 Origen seleccionado
📍 Sede seleccionada
⏳ Pendiente
📦 En preparación
🏪 Enviado a Shalom
🚚 En tránsito
✅ Entregado
❌ No entregado
Productos
Variante
Cant.
Subtotal
S/ 0.00
.
Total auto-calculadoS/ 0.00
SUBTOTAL PRODUCTOSS/ 0.00
DESCUENTO- S/ 0.00
TOTAL VENTAS/ 0.00
✏️ AJUSTE MANUALS/ 0.00
📦 COSTO PRODUCTOSS/ 0.00
🚚 COSTO ENVÍO (delivery)S/ 0.00
💰 COBRO ENVÍO (al cliente)S/ 0.00
📦 SUBSIDIO (empresa asume)S/ 0.00
💰 GANANCIA NETAS/ 0.00
Edita los métodos desde Configuración → Medios de pago
EVIDENCIAS INTERNASObligatorio
📸Cross Selling
🧾Evidencia Venta
Solo visible para el equipo, no para el cliente. Ambas fotos son obligatorias.
Fotos del pedidoSolo Admin/Logística
📦Foto Producto
🎫Foto Boleta
Fechas
Registro—
Envío
Entrega—
AGREGAR USUARIO
%de la ganancia neta por pedido
S/ fijo por cada producto vendidoConfigura el monto en Inventario → cada producto
Nombre de la instancia en el VPS. Dejar vacío si aún no tiene.
Comparte el email y contraseña para que inicie sesión
📱 Conectar WhatsApp
Esperando...
✅
WhatsApp conectado
El vendedor escanea el QR con su teléfono. Solo observa, no envía mensajes.
️
Empresa no encontrada
No existe ninguna empresa con ese identificador. Verifica el enlace que te compartieron.
RASTREA TU PEDIDO
Ingresa tu DNI y encuentra tu pedido al instante
SEGUIMIENTO EN TIEMPO REAL
Sin puntos ni espacios · Solo números
Datos seguros
Actualización en tiempo real
Sin registro requerido
¡Descuentos exclusivos para ti!
Deja tu email y recibe ofertas que no están en la tienda. Solo para clientes que ya compraron.
¡Tu pedido llegó a la agencia!
Ya está en Shalom, listo para ser despachado hacia ti. ¡Pronto llegará a tus manos!
En iPhone, las notificaciones solo funcionan si la app está instalada en tu pantalla de inicio.
1️⃣
Toca el ícono Compartir⬆ en Safari
2️⃣
Selecciona "Agregar a pantalla de inicio"
3️⃣
Abre la app desde el ícono y activa notificaciones
🔔
Recibe pedidos al instante
Activa las notificaciones y te avisamos en tu celular cuando llegue un pedido nuevo o cuando un envío lleve más de 6 horas sin enviarse a Shalom.
RECUPERAR CONTRASEÑA
Ingresa tu email y te enviaremos un enlace para restablecer tu contraseña.
RASTREA TU PEDIDO
Ingresa los datos para encontrar tu pedido
IMPORTAR EXCEL CON IA
Sube cualquier Excel con tus pedidos. La IA detecta automáticamente el formato y extrae los datos.
Arrastra tu Excel aquí
o haz clic para seleccionar · .xlsx / .xls
IA ANALIZANDO TU EXCEL
Leyendo el archivo...
PEDIDOS DETECTADOS
No se pudo analizar el archivo
IMPORTAR DESDE EXCEL (VBA)
CÓMO USAR EN EXCEL
1. Abre tu Excel → Alt + F11 (Editor VBA) 2. Inserta → Módulo → Pega el código de abajo 3. Selecciona las filas con pedidos en tu Excel 4. Ejecuta la macro → se copia el JSON al portapapeles 5. Pega aquí abajo y sube a TrackPro
Sub ExportarPedidosTrackPro()
Dim ws As Worksheet
Dim rng As Range
Dim cell As Range
Dim json As String
Dim rows() As String
Dim i As Integer
Set ws = ActiveSheet
Set rng = Selection
' Detectar columnas automaticamente buscando etiquetas
Dim colDNI As Integer, colNombre As Integer
Dim colTel As Integer, colProd As Integer
Dim colMonto As Integer, colProv As Integer
Dim colCiudad As Integer, colDir As Integer
colDNI = 0: colNombre = 0: colTel = 0
colProd = 0: colMonto = 0: colProv = 0
colCiudad = 0: colDir = 0
' Buscar fila de headers en las primeras 5 filas
Dim headerRow As Integer: headerRow = 0
Dim c As Integer, r As Integer
For r = 1 To 5
For c = 1 To ws.UsedRange.Columns.Count
Dim hdr As String
hdr = LCase(Trim(ws.Cells(r, c).Value))
If hdr = "dni" Or hdr = "documento" Then colDNI = c: headerRow = r
If InStr(hdr, "nombre") > 0 And colNombre = 0 Then colNombre = c
If InStr(hdr, "celular") > 0 Or InStr(hdr, "telefono") > 0 Then colTel = c
If InStr(hdr, "producto") > 0 Then colProd = c
If InStr(hdr, "monto") > 0 Or InStr(hdr, "total") > 0 Then colMonto = c
If InStr(hdr, "provincia") > 0 Or InStr(hdr, "region") > 0 Then colProv = c
If InStr(hdr, "ciudad") > 0 Or InStr(hdr, "distrito") > 0 Then colCiudad = c
If InStr(hdr, "direcc") > 0 Then colDir = c
Next c
If headerRow > 0 Then Exit For
Next r
' Si no hay headers, usar posiciones por defecto comunes
If headerRow = 0 Then
MsgBox "No se encontraron headers (NOMBRE, DNI, etc.)." & Chr(10) & _
"Asegurate que la primera fila tenga los nombres de columnas.", vbExclamation
Exit Sub
End If
json = "["
i = 0
Dim dataRow As Integer
For dataRow = headerRow + 1 To ws.UsedRange.Rows.Count
Dim dni As String, nombre As String
dni = ""
nombre = ""
If colDNI > 0 Then dni = Trim(CStr(ws.Cells(dataRow, colDNI).Value))
If colNombre > 0 Then nombre = Trim(ws.Cells(dataRow, colNombre).Value)
' Solo incluir filas con DNI de 8 digitos y nombre
If Len(dni) = 8 And IsNumeric(dni) And nombre <> "" Then
Dim tel As String, prod As String
Dim monto As String, prov As String
Dim ciudad As String, dir As String
tel = ""
prod = ""
monto = "0"
prov = ""
ciudad = ""
dir = ""
If colTel > 0 Then tel = Trim(CStr(ws.Cells(dataRow, colTel).Value))
If colProd > 0 Then prod = Replace(Trim(ws.Cells(dataRow, colProd).Value), """", "'")
If colMonto > 0 Then
Dim m As Double
m = 0
On Error Resume Next
m = CDbl(ws.Cells(dataRow, colMonto).Value)
On Error GoTo 0
monto = CStr(m)
End If
If colProv > 0 Then prov = Trim(ws.Cells(dataRow, colProv).Value)
If colCiudad > 0 Then ciudad = Trim(ws.Cells(dataRow, colCiudad).Value)
If colDir > 0 Then dir = Replace(Trim(ws.Cells(dataRow, colDir).Value), """", "'")
nombre = Replace(nombre, """", "'")
If i > 0 Then json = json & ","
json = json & Chr(10) & " {"
json = json & """nombre"":""" & nombre & ""","
json = json & """dni"":""" & dni & ""","
json = json & """telefono"":""" & tel & ""","
json = json & """productos"":[""" & prod & """],"
json = json & """monto"":" & monto & ","
json = json & """provincia"":""" & prov & ""","
json = json & """ciudad"":""" & ciudad & ""","
json = json & """direccion"":""" & dir & ""","
json = json & """estado"":""pendiente"","
json = json & """observaciones"":"""""""
json = json & "}"
i = i + 1
End If
Next dataRow
json = json & Chr(10) & "]"
If i = 0 Then
MsgBox "No se encontraron pedidos validos." & Chr(10) & _
"Verifica que haya filas con DNI de 8 digitos.", vbExclamation
Exit Sub
End If
' Copiar al portapapeles
Dim obj As Object
Set obj = CreateObject("Forms.TextBox.1")
obj.MultiLine = True
obj.Text = json
obj.SelectAll
obj.Copy
MsgBox i & " pedidos listos!" & Chr(10) & _
"El JSON fue copiado al portapapeles." & Chr(10) & _
"Pega en TrackPro y sube tus pedidos.", vbInformation, "TrackPro - Exportacion lista"
End Sub
PEDIDOS DETECTADOS
IMPORTAR DESDE GOOGLE SHEETS
Pega el link de tu Google Sheets. La IA lee las filas automáticamente y las sube a tu panel.
Antes de continuar
Tu Google Sheets debe ser público o accesible con el link: Compartir → Cualquier persona con el link → Lector
LEYENDO SHEETS
Conectando con Google Sheets...
PEDIDOS DETECTADOS
No se pudo leer el Sheets
️
Antes de continuar
Al usar este servicio de rastreo, aceptas que podemos procesar tu información
para gestionar tu pedido y enviarte comunicaciones relacionadas a tus compras.
Tus datos están protegidos conforme a la
Ley N° 29733 de Protección de Datos Personales y solo
se usarán para mejorar tu experiencia como cliente.
Datos seguros
Sin spam
Ley 29733
¿Tienes dudas?
Política de Privacidad
1. ¿Qué información recopilamos?
Recopilamos tu DNI para identificar tus pedidos, y opcionalmente tu correo electrónico si decides recibirlo para recibir actualizaciones de tus compras y beneficios exclusivos.
2. ¿Para qué usamos tus datos?
Tus datos se usan exclusivamente para: (a) mostrar el estado de tus pedidos, (b) enviarte notificaciones relacionadas a tus compras, y (c) ofrecerte beneficios exclusivos como cliente frecuente, siempre con tu consentimiento.
3. ¿Compartimos tu información?
No vendemos ni compartimos tus datos con terceros con fines comerciales ajenos a tu experiencia como cliente de nuestra tienda.
4. ¿Cómo protegemos tus datos?
Toda la información se almacena en servidores seguros con cifrado y se gestiona conforme a la Ley N° 29733 — Ley de Protección de Datos Personales del Perú y su reglamento.
5. Tus derechos (ARCO)
Tienes derecho a Acceder, Rectificar, Cancelar u Oponerte al tratamiento de tus datos personales. Para ejercer estos derechos, contacta directamente con la tienda que te compartió este enlace.
6. Cookies y almacenamiento local
Usamos almacenamiento local del navegador únicamente para recordar que ya aceptaste estas condiciones, evitando mostrarte este aviso repetidamente.