SuiteScript 2.x
Automatizaciones que aguantan volumen.
- Map/Reduce y Scheduled
- Suitelets y Client Scripts
- User Events y validaciones
Rodolfo Guerra · Especialista NetSuite
Llevo 7 años trabajando con NetSuite todos los días. Aquí comparto notas prácticas de desarrollo, consultas y administración: lo que funciona y los errores que conviene evitar.
Soy Rodolfo Guerra. Empecé administrando NetSuite en una empresa de servicios y hoy lidero el producto NetSuite de una empresa con varias subsidiarias.
Mi trabajo está entre el negocio y el sistema. Escucho qué necesita un área, lo traduzco a configuración o a código, y me aseguro de que siga funcionando cuando el volumen crece.
Creé este laboratorio para ordenar lo que aprendo y compartirlo. Cada nota sale de un caso real.
En qué me enfoco día a día.
Automatizaciones que aguantan volumen.
Respuestas claras a partir de los datos.
Un sistema ordenado y seguro.
Notas cortas, cada una basada en un caso real. Ábrelas para ver el detalle.
Un Scheduled Script que procesa todo en una sola ejecución va bien con pocos registros. Cuando el volumen crece, empiezan los problemas.
getInputData, map, reduce y summarize.summarize revisas qué falló y por qué.Regla práctica: Scheduled para tareas cortas y de volumen predecible. Map/Reduce para muchos registros o volumen que crece. Si dudas, empieza en Map/Reduce.
Antes: el mismo pago se digitaba en NetSuite, en la banca, en un Excel y en un correo al proveedor. Cuatro lugares, cuatro oportunidades de error.
Ojo: no todo viene de base. Con la SuiteApp Electronic Bank Payments tienes las plantillas estándar de tu país, aprobación por lotes y reversiones. Necesitan la licencia de Electronic Bank Payments: plantillas a medida, el procesamiento automático de facturas, multimoneda, APIs y el procesamiento en paralelo (este último, además, con SuiteCloud Plus).
| Error | Qué pasa | Cómo evitarlo |
|---|---|---|
| Sin External ID | Recargar duplica todo | Modo «Agregar o actualizar» + External ID |
| Listas que no coinciden | «Contado» ≠ «Contado - 0 días» | Texto idéntico al de NetSuite |
| Fechas en otro formato | Fechas rechazadas o mal leídas | El formato de fecha de tu usuario |
| Tildes y eñes rotas | «Perú» en vez de «Perú» | Archivo y carga en UTF-8 |
| Probar con todo el archivo | 500 registros por corregir | Primero 5 filas, luego el resto |
Extra: guarda el mapeo. La siguiente carga toma minutos.
Un cambio “pequeño” en producción puede romper:
Cuesta un día más. Un error en producción cuesta varios.
Un sistema externo envía el pedido A-1042 y NetSuite crea la orden. La respuesta no llega por un corte de red. El sistema reintenta… y sin protección, se crea una segunda orden.
La solución es que reintentar sea seguro (idempotencia). Usa el identificador del sistema externo como External ID: NetSuite no permite dos registros del mismo tipo con el mismo External ID.
// RESTlet (SuiteScript 2.1): buscar antes de crear
const previo = query.runSuiteQL({
query: 'SELECT id FROM transaction WHERE externalid = ?',
params: [payload.pedidoId]
}).asMappedResults()[0];
if (previo) return { id: previo.id, duplicado: true };
const orden = record.create({ type: record.Type.SALES_ORDER });
orden.setValue({ fieldId: 'externalid', value: payload.pedidoId });
Si el pedido ya existe, devuelves la misma orden. El External ID es la segunda barrera: aunque dos peticiones lleguen a la vez, NetSuite rechaza el duplicado.
BUILTIN.DF convierte un ID en el texto que ves en pantalla: el nombre del cliente, del vendedor o de la ubicación.
SELECT
t.tranid AS pedido,
BUILTIN.DF(t.entity) AS cliente,
BUILTIN.DF(t.employee) AS vendedor,
BUILTIN.DF(tl.location) AS ubicacion
FROM transaction t
JOIN transactionline tl
ON tl.transaction = t.id
WHERE t.type = 'SalesOrd'
AND tl.mainline = 'T'
AND t.status IN ('E', 'F')
Para mostrar, no para filtrar. En el WHERE usa siempre el ID o el código: es más eficiente y no depende de cómo se escribe el texto.
Si trabajas con NetSuite y quieres comentar alguna de estas notas, escríbeme por LinkedIn.
Ir a mi LinkedIn ↗