Apex Academy
Módulo 1·Checkpoint·45 min

Checkpoint del Módulo 1

Las nueve sub-lecciones, un caso de negocio real resuelto con todas ellas, y un quiz que no se aprueba de memoria.

En Admin esUn caso real de Sales Cloud con las nueve piezas

✓ En esta sub-lección

  1. 01Reconstruir de memoria qué resuelve cada sub-lección y por qué está donde está.
  2. 02Leer un bloque de Apex real e identificar de dónde sale cada decisión.
  3. 03Escribir código que sobreviva a datos incompletos sin haber visto todavía un if.

La nutria: ¿Te acuerdas? · Repaso de la lección 9

¿Cómo conviertes el texto '25' en un número entero?

Un módulo de fundamentos parece una lista de tipos hasta que ves las nueve piezas trabajando juntas sobre un registro real. Esa es exactamente la diferencia entre saber qué es un Decimal y saber cuándo usarlo.

Lo que has aprendido, sub-lección a sub-lección

1 · Variables y declaración. Declarar una variable es el asistente de campo personalizado en una línea: eliges el tipo antes que el valor, le pones nombre y decides si podrá cambiar. Integer maxDiscount = 20; tiene cuatro partes y todas hacen falta. Importa porque el tipo es una promesa que la plataforma verifica al compilar, y esa rigidez convierte errores de ejecución (los que ve el cliente) en errores de guardado, que solo ves tú.

2 · Tipos numéricos y Boolean. Es el mismo desplegable de «Number, Currency, Percent, Checkbox», con consecuencias más visibles: Decimal para dinero, Integer para lo que se cuenta, Boolean para lo que solo admite sí o no. Decimal total = units * 19.99; suena inocente hasta que descubres que 9 / 4 entre Integers da 2. Y aquí aparecen los dos tipos que solo existen porque esto es Salesforce: Id, que valida el formato de un identificador, y Blob, que guarda el archivo en bruto.

3 · String y qué es un método. Un método es una acción con nombre que un dato sabe hacer consigo mismo: lo que en fórmulas era TRIM(Name), aquí es name.trim(). Devuelve siempre un valor nuevo y nunca modifica el original, así que String clean = raw.trim(); guarda el trabajo y raw.trim(); lo tira. Como cada método devuelve un valor, se pueden encadenar (raw.trim().toUpperCase(), de izquierda a derecha) y anidar (String.valueOf(total.setScale(2)), de dentro hacia fuera, como TEXT(ROUND(Amount, 2))). En este checkpoint verás las dos cosas. Importa porque es el primer sitio donde se ve que en Apex los datos no son inertes: tienen comportamiento.

4 · Date, Time y Datetime. Los tres tipos de fecha del asistente, con la misma trampa: solo Datetime lleva zona horaria, y por eso un pedido de las 00:30 cambia de día según quién lo mire. Date renewal = signed.addYears(1); calcula en vez de escribir, y addMonths() ya sabe que febrero tiene 28. Importa porque una fecha mal tipada no da error: da un informe que no cuadra y nadie sabe por qué.

5 · sObjects. Object Manager define el molde; new Account() fabrica una fila con ese molde, y el punto significa «el campo de». Account a = new Account(Name = 'Acme'); crea un registro que existe solo en memoria: su Id está vacío y desaparece al acabar la transacción. Importa porque marca la frontera entre «tengo el dato delante» y «el dato está guardado», que es la frontera donde empiezan los módulos de y .

6 · Null. Es el campo en blanco de siempre, pero aquí no se ignora educadamente: pedirle un método a null detiene la transacción con un NullPointerException. String.isBlank(region) cubre de una vez el null, la cadena vacía y la de espacios, que es exactamente lo que manda un formulario web. Importa porque es la causa número uno de errores en Apex y la más barata de evitar: una comprobación de una línea.

7 · Operadores. Los mismos símbolos que usabas en una regla de validación, con dos añadidos decisivos: && evalúa en corto, así que region != null && region.length() > 2 es seguro y el orden inverso explota; y el operador condicional es el IF() de las fórmulas escrito como condición ? a : b. Importa porque es lo que te permite decidir sin haber visto todavía un if, y porque el orden de las condiciones no es estilo: es estabilidad.

8 · Colecciones. List es la lista relacionada (orden y repetidos), Set es la columna de agrupación de un informe (valores únicos) y Map es el cruce por Id que harías en una hoja de cálculo. Map<String, Decimal> quotaByRegion = new Map<String, Decimal>(); responde «¿cuál es la cuota de EMEA?» sin recorrer nada. Importa porque a partir del Módulo 3 todo llega en bloques de 200 registros, y elegir mal la colección es la diferencia entre código que aguanta y código que agota los .

9 · Casting y conversión. Es la advertencia de Setup al cambiar un campo de Texto a Número, hecha explícita: hacia arriba Apex convierte solo, hacia abajo lo pides tú con intValue() o setScale(), y entre texto y número nunca hay automatismo: hace falta Integer.valueOf('42'). El casting de verdad, (Account) record, no transforma nada: cambia cómo mira Apex un valor, y si te equivocas el error llega en ejecución. Importa porque los datos de integraciones y formularios siempre llegan como texto.


El caso real: ficha de oportunidad para dirección

Dirección de Ventas quiere una ficha resumen por oportunidad: nombre limpio, código corto, importe con impuestos, si necesita aprobación, cuántos días faltan para el cierre y qué cuota tiene la región del cliente. Los datos llegan como llegan: el nombre con espacios y en minúsculas, la región del cliente sin rellenar. El código de abajo resuelve el caso completo usando las nueve sub-lecciones, y sin una sola condición ni un solo bucle, porque todavía no los has visto.

Apex
// ─── L5 · sObjects: los registros, todavía solo en memoria ───────────────
Opportunity opp = new Opportunity(
    Name      = '  renovación northwind  ',
    StageName = 'Negotiation',
    CloseDate = Date.newInstance(2026, 6, 30),
    Amount    = 24500.75
);
Account customer = new Account(Name = 'Northwind Trading');
// customer.Region__c se queda sin asignar: el formulario lo envió vacío.

// ─── L1 · Variables + L2 · Tipos: constantes del negocio ─────────────────
final Decimal TAX_RATE = 0.21;             // dinero → Decimal
final Integer BIG_DEAL_THRESHOLD = 20000;  // umbral contable → Integer

// ─── L3 · String: limpiar lo que llega sucio ─────────────────────────────
String cleanName = opp.Name.trim().capitalize();
String opportunityCode = cleanName.substring(0, 4).toUpperCase();

// ─── L6 · Null + L7 · Operadores: decidir qué hacer con los huecos ───────
Decimal safeAmount = opp.Amount == null ? 0 : opp.Amount;
String displayRegion = String.isBlank(customer.Region__c)
    ? 'Sin región'
    : customer.Region__c;

// ─── L7 · Operadores: las reglas de negocio, una a una ───────────────────
Decimal amountWithTax = safeAmount * (1 + TAX_RATE);
Boolean isBigDeal = safeAmount >= BIG_DEAL_THRESHOLD;
Boolean isNegotiating = opp.StageName == 'Negotiation';
Boolean needsApproval = isBigDeal && isNegotiating;

// ─── L4 · Fechas: cuentas sobre el calendario, no sobre días sueltos ─────
Integer daysToClose = Date.today().daysBetween(opp.CloseDate);
Date internalReviewDate = opp.CloseDate.addDays(-15);

// ─── L8 · Colecciones: la tabla de cuotas y el resumen ───────────────────
Map<String, Decimal> quotaByRegion = new Map<String, Decimal>();
quotaByRegion.put('EMEA', 150000);
quotaByRegion.put('AMER', 220000);

Decimal regionQuota = quotaByRegion.containsKey(displayRegion)
    ? quotaByRegion.get(displayRegion)
    : 0;

List<String> summaryLines = new List<String>();
summaryLines.add(opportunityCode + ' · ' + cleanName);
summaryLines.add('Región: ' + displayRegion);
summaryLines.add(needsApproval ? 'Requiere aprobación' : 'Aprobación no necesaria');

// ─── L9 · Casting: de número a texto para mostrarlo ──────────────────────
String amountLabel = String.valueOf(amountWithTax.setScale(2));
summaryLines.add('Importe con IVA: ' + amountLabel);

System.debug(summaryLines);
Ni un if ni un for, y el caso queda resuelto, incluida la región que nunca llegó.
final Decimal TAX_RATE = 0.21;

Paso 1 de 6

Se empieza eligiendo tipos: Decimal para el dinero y final para lo que no debe cambiar. Esa decisión de treinta segundos es la que evita que el impuesto se toque por accidente más abajo.

Diagrama 1 · El flujo del ejemplo, paso a paso, etiquetado por la sub-lección de la que sale cada bloque.

El concepto puente: campo fórmula frente a Apex

Casi todo lo de este módulo tiene un equivalente en un campo fórmula, y por eso te ha resultado familiar. La diferencia no está en lo que se puede calcular, sino en dónde vive el cálculo, cuándo ocurre y cuántos registros puede tocar. Ese salto es lo que justifica todo lo que viene después.

CAMPO FÓRMULA

APEX

Dónde vive

En un campo del objeto

En clases y triggers

Paso 1 de 5

Una fórmula pertenece a un objeto y solo existe dentro de él. Apex vive aparte, en archivos que pueden tocar cualquier objeto de la org.

Diagrama 2 · Lo mismo que ya sabías hacer con clicks, y lo que se abre al escribirlo en código.

Por qué el módulo va en este orden

No es un índice arbitrario. Los tipos básicos sostienen a los sObjects, los sObjects hacen que null deje de ser una curiosidad y pase a ser el caso habitual, y sin entender null no se pueden usar bien ni los operadores ni las colecciones ni las conversiones: las tres tienen un camino donde aparece un hueco.

    • 1 · Variables

Paso 1 de 5

Todo arranca aquí: sin declarar una variable no hay dónde meter nada. Es el «elige el tipo» del asistente de campo, y ninguna de las otras ocho sub-lecciones se sostiene sin esto.

Diagrama 3 · Qué sub-lección necesita a cuál. Si algo de la fila de abajo se te resistió, la respuesta suele estar más arriba.