Checkpoint del Módulo 8
La entrega: el importador nocturno completo. Una consulta para todas las filas, un try por fila, guardado parcial y un informe para el ERP que sale pase lo que pase.
✓ En esta sub-lección
- 01Combinar try por fila, excepción propia y guardado parcial en un mismo proceso.
- 02Leer los fallos de cada registro con SaveResult: isSuccess() y getErrors().
- 03Traducir cada herramienta de errores de Flow a su equivalente en Apex.
La nutria: ¿Te acuerdas? · Repaso de la lección 5
El guardián marca una renovación duplicada con addError y el ERP guardó con Database.insert(list, false). ¿Qué pasa?
Cinco tareas preparando piezas: un try que no deja caer la importación, los tipos, throw, tu excepción y el guardián con addError. Esta es la tarea en la que se montan. El proceso nocturno llama a RenewalImporter.run con las filas del ERP, y por la mañana el ERP espera dos cosas: las renovaciones buenas creadas y una lista de las malas con su motivo.
Lo que has construido, pieza por pieza
| Pieza | Qué resuelve | Tarea |
|---|---|---|
| try / catch / finally | Una fila mala no tumba las demás, y lo del finally se ejecuta siempre. | 1 |
| Varios catch por tipo | Cada fallo tratado según lo que es, del más concreto al más general. | 2 |
| throw y propagación | El método valida y avisa; decide quien lo llama. | 3 |
| RenewalImportException | Los errores del negocio con nombre propio; los bugs no se esconden. | 4 |
| addError | El trigger rechaza una fila sin tumbar el lote. | 5 |
| Database.insert(list, false) + SaveResult | Guardar lo que se pueda y saber qué falló y por qué, registro a registro. | 6 |
EN FLOW USABAS… ·aciertos 0/0
El fault path de un elemento
Paso 1 de 7
Elige su pieza en Apex.
La entrega: el importador completo
run recibe un Map de código ERP → importe en texto. Primero, una sola consulta trae todas las cuentas cuyo ERP_Code__c está entre las claves, y un Map<String, Account> las deja a mano (Módulo 4). Después, cada fila en su propio try: si el código no está en el mapa o el importe no sirve, salta una RenewalImportException, se apunta en el informe y el bucle sigue. Las filas que pasan van a una lista que se guarda de una vez con Database.insert(toInsert, false).
Ese guardado todavía puede rechazar filas que el bucle no podía prever: el guardián de la tarea 5 con su addError, o una cuenta cuyo propietario es un usuario inactivo (INACTIVE_OWNER_OR_USER). Database.insert devuelve una lista de SaveResult en el mismo orden que toInsert: results[i] habla de toInsert[i]. isSuccess() dice si se guardó y getErrors() trae el motivo.
List<Database.SaveResult> results = Database.insert(toInsert, false);
for (Integer i = 0; i < results.size(); i++) {
if (!results[i].isSuccess()) {
Database.Error err = results[i].getErrors()[0];
report.add(toInsert[i].Name + ' · ' + err.getStatusCode() + ' · ' + err.getMessage());
}
}La nutria: ¿Y por qué no un Flow? Porque el ERP necesita la lista
Lo que viene: el Módulo 9
El importador ya aguanta 300 filas. ¿Y 300.000? No caben en una transacción, por mucho que bulkifiques. Para eso Apex tiene trabajo asíncrono: procesos que se trocean y se ejecutan en segundo plano. Es el Módulo 9.