Está en la página 1de 52

Salesforce

#salesforce
Tabla de contenido
Acerca de 1

Capítulo 1: Empezando con Salesforce 2

Observaciones 2

Examples 2

Instalación o configuración 2

Productos Salesforce 2

Nube de ventas 2

Nube de servicios 2

Nube de marketing 2

Nube comunitaria 2

Analytics Cloud aka Wave Analytics 3

App Cloud 3

Nube de IoT 3

Productos específicos de la industria 3

Nube de servicios financieros 3

Nube de salud 3

Heroku 3

Capítulo 2: Ajustes personalizados 4

Observaciones 4

Introducción 4

Lista de configuraciones personalizadas 4

Examples 5

Creación y gestión de configuraciones personalizadas 5

Creación 5

administración 5

Uso de la configuración personalizada de la jerarquía para deshabilitar el flujo de trabaj 6

Configuración personalizada 6

Campo de configuración personalizada 7

Valor de campo de configuración personalizada 7

Regla de validación 8
Reglas de flujo de trabajo 9

Uso de la configuración personalizada de la jerarquía para deshabilitar el código de Apex 9

Explicación 9

Clase de Apex 9

Prueba de unidad 9

Actualización de las configuraciones personalizadas de la jerarquía en el código de Apex 11

Capítulo 3: Apex Testing 16

Examples 16

Afirmar métodos 16

Clase de prueba basica 16

Utilizando testSetup 17

Utilizando bloques estáticos 17

Metodos de afirmacion 18

Capítulo 4: Apex Triggers 19

Sintaxis 19

Parámetros 19

Examples 19

Disparador basico 19

Variables de contexto de disparo 19

Manipulando registros que dispararon el gatillo. 20

Capítulo 5: API REST de Salesforce 22

Introducción 22

Examples 22

OAuth2 access_token y lista de servicios 22

Capítulo 6: Bulkificación del gatillo 23

Examples 23

Bulkificación 23

Capítulo 7: Desarrollo de la página de Visualforce 24

Examples 24

Pagina basica 24

Uso de controladores estándar 24

Capítulo 8: Herramientas para el desarrollo 26


Examples 26

IDEs 26

Extensiones de navegador 26

Depuradores 26

Herramientas de Salesforce ETL 27

Herramientas de análisis estático 27

Capítulo 9: Lenguaje de consulta de objetos de Salesforce (SOQL) 28

Sintaxis 28

Examples 28

Consulta SOQL básica 28

Consulta SOQL Con Filtrado 28

Consulta de SOQL con pedidos 29

Usando SOQL para construir un mapa 29

Consulta de SOQL para hacer referencia a los campos del objeto principal 29

Consultas SOQL en Apex 30

Referencias de variables en las consultas de Apex SOQL 30

Posibles excepciones en las consultas de Apex SOQL 30

Usando un Semi-Join 31

SOQL dinámico 31

Capítulo 10: Manipulación de fecha y hora 32

Examples 32

Encuentra fácilmente el último día de un mes 32

Capítulo 11: Navegación de la página con la ayuda de la clase envoltura de lista en la fue 33

Introducción 33

Examples 33

Controlador de paginación 33

Capítulo 12: Procesos de aprobación de objetos 37

Observaciones 37

Examples 38

ProcesoDefinición 38

ProcessNode 39

ProcessInstance 39
ProcessInstanceStep & ProcessInstanceWorkitem 39

ProcessInstanceHistory * 40

Capítulo 13: SalesForce Integración CI 41

Introducción 41

Examples 41

¿Cómo configurar Jenkins para implementar código en desarrollo o producción org? 41

Herramientas Jenkins CI que se pueden utilizar para la automatización de SalesForce 41

Capítulo 14: Trabajando con Sistemas Externos 43

Examples 43

Hacer una llamada saliente 43

Capítulo 15: Variables globales en las clases 44

Introducción 44

Examples 44

Información de usuario 44

Capítulo 16: Variables globales en las páginas de Visualforce 45

Examples 45

$ Recurso 45

$ Etiqueta 45

$ Usuario 45

Creditos 46
Acerca de
You can share this PDF with anyone you feel could benefit from it, downloaded the latest version
from: salesforce

It is an unofficial and free Salesforce ebook created for educational purposes. All the content is
extracted from Stack Overflow Documentation, which is written by many hardworking individuals at
Stack Overflow. It is neither affiliated with Stack Overflow nor official Salesforce.

The content is released under Creative Commons BY-SA, and the list of contributors to each
chapter are provided in the credits section at the end of this book. Images may be copyright of
their respective owners unless otherwise specified. All trademarks and registered trademarks are
the property of their respective company owners.

Use the content presented in this book at your own risk; it is not guaranteed to be correct nor
accurate, please send your feedback and corrections to info@zzzprojects.com

https://riptutorial.com/es/home 1
Capítulo 1: Empezando con Salesforce
Observaciones
Esta sección proporciona una descripción general de qué es Salesforce y por qué un
desarrollador puede querer usarlo.

También debe mencionar cualquier tema importante dentro de la fuerza de ventas y vincular a los
temas relacionados. Dado que la Documentación para salesforce es nueva, es posible que deba
crear versiones iniciales de los temas relacionados.

Examples
Instalación o configuración

La mejor manera de comenzar con Salesforce es obtener su propia Edición para desarrolladores.

Developer Edition (a menudo denominado "DE org") es un entorno de desarrollo con todas las
funciones con límites en cuanto a datos y usuarios. Developer Edition es donde puede
familiarizarse con el entorno, probar cosas y jugar en Salesforce.com. Developer Edition es un
entorno que le permite comenzar a desarrollar, probar y desplegar instantáneamente su
aplicación en la nube.

Productos Salesforce

La aplicación Salesforce consta de varios productos que pueden integrarse entre sí:

Nube de ventas
Página de Marketing , Documentación Salesforce

Nube de servicios
Página de marketing , documentación de Salesforce , Trailhead

Nube de marketing
Página de Marketing

Nube comunitaria
Página de Marketing , Documentación Salesforce

https://riptutorial.com/es/home 2
Analytics Cloud aka Wave Analytics
Página de marketing , documentación de Salesforce , Trailhead

App Cloud
Página de Marketing

Nube de IoT
Página de Marketing

Productos específicos de la industria

Nube de servicios financieros


Página de Marketing , Documentación Salesforce

Nube de salud
Página de Marketing , Documentación Salesforce

Heroku
Página de Marketing

Lea Empezando con Salesforce en línea:


https://riptutorial.com/es/salesforce/topic/3768/empezando-con-salesforce

https://riptutorial.com/es/home 3
Capítulo 2: Ajustes personalizados
Observaciones

Introducción
A diferencia de los objetos personalizados que tienen registros basados en ellos, la configuración
personalizada le permite utilizar conjuntos de datos personalizados en su organización, o
distinguir usuarios particulares o perfiles según criterios personalizados. Esto significa, por
ejemplo, que los administradores pueden editar las configuraciones personalizadas de la jerarquía
para desactivar las Reglas de flujo de trabajo / validación para usuarios individuales o perfiles, sin
tener que desactivarlas para toda la organización (consulte el ejemplo Uso de las configuraciones
personalizadas de la jerarquía para desactivar las Reglas de flujo de trabajo / validación arriba) ).

Las reglas de validación generalmente deben desactivarse temporalmente cuando:

• El código está actualizando los registros antiguos, que se editaron por última vez antes de
que se activara una regla de validación y, por lo tanto, no cumplen con los criterios de la
regla más reciente.
• El código es insertar nuevos registros sin los valores requeridos por los criterios de una
regla de validación.

Las reglas de flujo de trabajo comúnmente deben desactivarse temporalmente cuando:

• Activarían una alerta por correo electrónico o una actualización de campo que sobrescribiría
o interferiría con los cambios que está realizando en el registro.

El uso de una configuración personalizada otorga a los administradores cierto control declarativo
sobre el código, por lo que uno de los muchos casos de uso es que, cuando se utiliza, puede
hacer que no sea necesario implementar el código para deshabilitar los desencadenantes
(consulte el ejemplo de Uso de la configuración de jerarquía personalizada para deshabilitar el
código de Apex). ).

Un beneficio clave para los desarrolladores es que los datos de configuración personalizada se
exponen en el caché de la aplicación, lo que permite un acceso eficiente sin el costo de consultas
repetidas a la base de datos. Estos datos pueden ser utilizados por campos de fórmula, reglas de
validación, flujos, Apex y la API SOAP; consulte la documentación de Salesforce .

Los límites y consideraciones para la configuración personalizada se documentan aquí .

Lista de configuraciones personalizadas


También es posible crear Configuraciones personalizadas de lista, los casos de uso comunes
incluyen el almacenamiento de abreviaturas de estado de dos letras, prefijos de marcación
internacional y números de catálogo para productos. Sin embargo, Salesforce ahora está

https://riptutorial.com/es/home 4
promoviendo el uso de Tipos de metadatos personalizados, en lugar de Listar configuraciones
personalizadas.

Cuando vaya a crear una nueva configuración personalizada, se mostrará el siguiente mensaje

Consejo: use tipos de metadatos personalizados para la configuración de la


aplicación
Si está pensando en utilizar la configuración personalizada de la lista, considere usar
tipos de metadatos personalizados en su lugar. A diferencia de la configuración
personalizada de la lista, puede migrar los registros de los tipos de metadatos
personalizados mediante el uso de paquetes o herramientas de API de metadatos.

Los tipos de metadatos personalizados tienen beneficios adicionales frente a la lista de


configuraciones personalizadas como se describe en esta respuesta . Y de acuerdo con el
desarrollador líder de CMDs "Hay mucho más planeado para los tipos de metadatos
personalizados que las configuraciones personalizadas en esteroides".

Examples
Creación y gestión de configuraciones personalizadas

Creación
Para crear una configuración personalizada, vaya a:

Clásico
Configuración> Desarrollar> Configuraciones personalizadas> Nuevo

Relámpago
Configuración> Código personalizado> Configuración personalizada> Nuevo

Cree su configuración (consulte las Observaciones más adelante en este documento para ver las
diferencias entre las configuraciones personalizadas de Jerarquía y Lista). Puede ignorar la lista
de selección Visibilidad, a menos que planee implementar su configuración en un paquete
administrado.

Para crear los campos de configuración, haga clic en el botón Nuevo y siga el proceso habitual
para crear un campo personalizado.

administración
Una vez que haya creado su (s) campo (s), puede comenzar a configurar la configuración
haciendo clic en el botón Administrar.

Es más fácil administrar la configuración si crea una nueva vista e incluye cualquier campo que
haya creado para brindarle una visión general completa de la configuración, de un vistazo. El
propietario de la instalación es el usuario o el perfil al que se aplica la configuración.

https://riptutorial.com/es/home 5
Para administrar la configuración en el nivel de organización, haga clic en el botón Nuevo sobre el
encabezado Valor de nivel de organización predeterminado (en el cuadro rojo a continuación).

Para administrar la configuración a nivel de usuario o perfil, haga clic en el botón Nuevo en el
cuadro azul a continuación.

Uso de la configuración personalizada de la jerarquía para deshabilitar el flujo


de trabajo / reglas de validación

Configuración personalizada

https://riptutorial.com/es/home 6
Campo de configuración personalizada

Valor de campo de configuración personalizada


Cuando se marque el campo, se desactivará la regla de validación, para el usuario en ejecución

https://riptutorial.com/es/home 7
o, en este ejemplo, su perfil:

La regla también se puede deshabilitar para toda una organización de Salesforce:

Regla de validación

AND(
/* the below is the reference to the Val_Rule_Cntrlr__c custom setting's checkbox field
All_Opportunity_Disabled__c
*/
$Setup.Val_Rule_Cntrlr__c.All_Opportunity_Disabled__c = FALSE,

/* the below is the remainder of the validation rule's formula


*/
CloseDate < TODAY()
)

https://riptutorial.com/es/home 8
En la regla anterior, ambos criterios deben evaluarse en TRUE para que se TRUE la regla.

Dado que la casilla de verificación All_Opportunity_Disabled__c se evaluará como TRUE cuando el


perfil del usuario en ejecución sea Administrador del sistema, la regla se evaluará como FALSE .

Reglas de flujo de trabajo


Se puede aplicar el mismo enfoque para desactivar las Reglas de flujo de trabajo.

Uso de la configuración personalizada de la jerarquía para deshabilitar el


código de Apex

Explicación
En este ejemplo, se creó un Desencadenador simple para cambiar la Fecha de Cierre de una
Oportunidad, que está a punto de insertarse o actualizarse, a una fecha de 10 días en el futuro.

El campo de la casilla de verificación de la configuración personalizada de Apex Controller


permite que el código se deshabilite en el nivel de usuario / perfil / organización.

Clase de Apex

trigger CloseDateUpdate on Opportunity (before insert, before update) {

Id userId;
Apx_Cntrlr__c userApexController;
Boolean userSetting;

userId = userinfo.getUserId();
userApexController = Apx_Cntrlr__c.getInstance(userId);
userSetting = userApexController.Close_Date_Update_Disabled__c;

if (userSetting == false) {
for(Opportunity opp : Trigger.new) {
opp.CloseDate = date.today().addDays(10);
}
}

Prueba de unidad

@isTest
public class CloseDateUpdateTest {

@testSetup
static void dataSetup() {

Profile p = [SELECT Id FROM Profile WHERE Name = 'System Administrator' LIMIT 1];

https://riptutorial.com/es/home 9
User u = new User(LastName = 'Test',Alias = 't1',Email = 'example@gmail.com',Username
= 'sotest@gmail.com',ProfileId = p.Id,TimeZoneSidKey = 'America/Denver',LocaleSidKey =
'en_US',EmailEncodingKey = 'UTF-8',LanguageLocaleKey = 'en_US');
insert u;
}

static testMethod void testCloseDateUpdateEnabled() {

User u = [SELECT Id FROM User WHERE Username = 'sotest@gmail.com'];


// set the custom setting field to FALSE so that the trigger is not deactivated
Apx_Cntrlr__c apexController = new Apx_Cntrlr__c(SetupOwnerId =
u.Id,Close_Date_Update_Disabled__c = false);
upsert apexController;

Opportunity[] opportunities1 = new Opportunity[]{};

test.startTest();
system.runAs(u){

for(integer i = 0; i < 200; i++) {


opportunities1.add(new Opportunity(
Name = 'Test Opp ' + i,
OwnerId = u.Id,
StageName = 'Prospecting',
CloseDate = date.today().addDays(1),
Amount = 100));
}
insert opportunities1;
}
test.stopTest();

List<Opportunity> opportunities2 = [SELECT CloseDate FROM Opportunity];

for(Opportunity o : opportunities2){
system.assertEquals(date.today().addDays(10), o.closeDate, 'CloseDateUpdate
trigger should have changed the Opportunity close date as it was not disabled by the
apexController custom setting');
}
}

static testMethod void testCloseDateUpdateDisabled() {

User u = [SELECT Id FROM User WHERE Username = 'sotest@gmail.com'];


// set the custom setting field to TRUE to deactivate the trigger
Apx_Cntrlr__c apexController = new Apx_Cntrlr__c(SetupOwnerId =
u.Id,Close_Date_Update_Disabled__c = true);
upsert apexController;

Opportunity[] opportunities1 = new Opportunity[]{};

test.startTest();
system.runAs(u){

for(integer i = 0; i < 200; i++) {


opportunities1.add(new Opportunity(
Name = 'Test Opp ' + i,
OwnerId = u.Id,
StageName = 'Prospecting',
CloseDate = date.today().addDays(1),
Amount = 100));
}

https://riptutorial.com/es/home 10
insert opportunities1;
}
test.stopTest();

List<Opportunity> opportunities2 = [SELECT CloseDate FROM Opportunity];

for(Opportunity o : opportunities2){
system.assertEquals(date.today().addDays(1), o.closeDate, 'CloseDateUpdate trigger
should not have changed the Opportunity close date as it was disabled by the apexController
custom setting');
}
}

Actualización de las configuraciones personalizadas de la jerarquía en el


código de Apex

Es posible que desee actualizar la configuración personalizada durante la ejecución de su código,


para desactivar las reglas de validación o flujo de trabajo.

En el código a continuación, he creado una Clase de Apex programable que actualizará la Fecha
de cierre de cualquier oportunidad cuya Fecha de cierre sea inferior o igual a 6 días a partir de la
fecha actual, cambiando la fecha a 20 días en el futuro.

Usaré mi Configuración personalizada Val_Rule_Cntrlr__c para desactivar cualquier regla de


validación que me impida actualizar las oportunidades que cumplan con mis criterios.

global class Scheduled_OppCloseDateUpdate implements Schedulable {

global void execute(SchedulableContext SC) {


updOpportunityCloseDates();
}

global void updOpportunityCloseDates() {

Id userId;
Val_Rule_Cntrlr__c setting;
Boolean validationRulesAlreadyDisabled;
List<Opportunity> processedOpps = new List<Opportunity>();
Date d;

// get running user's Id


userId = userinfo.getUserId();
// retrieve Custom Setting status, for running user
setting = Val_Rule_Cntrlr__c.getInstance(userId);

// if the setting field is false, update it to disable validation rules


if (setting.All_Opportunity_Disabled__c == false) {
setting.All_Opportunity_Disabled__c = true;
upsert setting;
}
// if the setting field was already true, there's no need to disable it
// but it shouldn't be switched to false by this class once the process has been
completed
else {
validationRulesAlreadyDisabled = true;

https://riptutorial.com/es/home 11
}

// execute code to manage business process

d = system.today().addDays(6);

for(Opportunity o : [SELECT Id, CloseDate


FROM Opportunity
WHERE CloseDate <= :d
// class only updates open Opportunities
AND Probability > 0 AND Probability < 100])
{
o.CloseDate = System.today().addDays(20);
processedOpps.add(o);
}

if (processedOpps.size() > 0) {
update processedOpps;
}

// reactivate validation rules


if (validationRulesAlreadyDisabled == false) {
setting.All_Opportunity_Disabled__c = false;
upsert setting;
}

Para asegurarme de que mis reglas de validación están siendo desactivadas por los cambios en
mi configuración personalizada en mi clase, he creado un campo de casilla de verificación
Trigger_Validation_Rule__c (que no sería visible para los usuarios o agregado a los diseños de
página) y una regla de validación con este criterio:

AND(
$Setup.Val_Rule_Cntrlr__c.All_Opportunity_Disabled__c = FALSE,
Trigger_Validation_Rule__c = TRUE,

/* allow the above criteria to be met while inserting the Opportunities, without triggering
the rule, in the @testSetup portion of the test */
NOT(ISNEW())
)

Luego, establezco el campo de la casilla de verificación en true al crear mis Oportunidades para
que se cumplan los criterios de las reglas, si el campo de configuración personalizada no es
editado por mi código.

@isTest
private class WE_ScheduledCloseDateUpdateTest {

@testSetup
static void dataSetup() {

Profile p = [SELECT Id FROM Profile WHERE Name = 'System Administrator' LIMIT 1];

User u = new User(LastName = 'Test',Alias = 't1',Email = 'example@gmail.com',Username

https://riptutorial.com/es/home 12
= 'sotest@gmail.com',ProfileId = p.Id,TimeZoneSidKey = 'America/Denver',LocaleSidKey =
'en_US',EmailEncodingKey = 'UTF-8',LanguageLocaleKey = 'en_US');
insert u;

Val_Rule_Cntrlr__c valRuleCntrlr = new Val_Rule_Cntrlr__c(SetupOwnerId =


u.Id,All_Opportunity_Disabled__c = false);
upsert valRuleCntrlr;

List<Opportunity> testOpps = new List<Opportunity>();

// create the Opportunities that will be updated by the class


for(integer i = 0; i < 200; i++) {
testOpps.add(new Opportunity(
Name = 'Test Opp Update' + i,
OwnerId = u.Id,
StageName = 'Prospecting',
CloseDate = date.today().addDays(1),
Amount = 100,
// set checkbox field to true, to trigger validation rules if they've not been
deactivated by class
Trigger_Validation_Rule__c = true));
}
// create the Opportunities that won't be updated by the class
for(integer i = 0; i < 200; i++) {
testOpps.add(new Opportunity(
Name = 'Test Opp Skip' + i,
OwnerId = u.Id,
StageName = 'Prospecting',
CloseDate = date.today().addDays(15),
Amount = 100,
Trigger_Validation_Rule__c = true));
}
insert testOpps;

// code required to test a scheduled class, see


https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_scheduler.htm
for more details
public static String CRON_EXP = '0 0 0 15 3 ? 2022';

static testmethod void testCloseDateUpdates() {

// execute scheduled class

Test.startTest();

String jobId = System.schedule('ScheduleApexClassTest',


CRON_EXP,
new Scheduled_OppCloseDateUpdate());

CronTrigger ct = [SELECT Id, CronExpression, TimesTriggered, NextFireTime


FROM CronTrigger
WHERE id = :jobId];

System.assertEquals(CRON_EXP, ct.CronExpression);
System.assertEquals(0, ct.TimesTriggered);
System.assertEquals('2022-03-15 00:00:00', String.valueOf(ct.NextFireTime));

Test.stopTest();

https://riptutorial.com/es/home 13
// test results

Integer updateCount = 0;
Integer skipCount = 0;

List <Opportunity> opportunitys = [SELECT Id, Name, CloseDate FROM Opportunity];

for(Opportunity o : opportunitys) {
if (o.Name.contains('Update') &&
updateCount == 0)
{
System.assertEquals(date.today().addDays(20), o.CloseDate, 'Opportunity\'s
Close Date should have been updated as it was less than 7 days away');
updateCount = 1;
}
if (o.Name.contains('Skip') &&
skipCount == 0)
{
System.assertEquals(date.today().addDays(15), o.CloseDate, 'Opportunity should
not have been updated as it\'s Close Date is more than 7 days away');
skipCount = 1;
}
}
// check that both lists of Opportunities have been tested
System.assertEquals(2, updateCount + skipCount, 'Count should be 2 once all assertions
have been executed');

// check that the class does not change the custom setting's field to false, if it was
true before class was executed
static testmethod void testSettingUpdates() {

User u = [SELECT Id FROM User WHERE UserName = 'sotest@gmail.com'];

// switch the custom setting field to true before the scheduled job executes
Val_Rule_Cntrlr__c setting;
setting = Val_Rule_Cntrlr__c.getInstance(u.Id);
setting.All_Opportunity_Disabled__c = true;
upsert setting;

System.runAs(u) {

Test.startTest();

String jobId = System.schedule('ScheduleApexClassTest',


CRON_EXP,
new Scheduled_OppCloseDateUpdate());

CronTrigger ct = [SELECT Id, CronExpression, TimesTriggered, NextFireTime


FROM CronTrigger
WHERE id = :jobId];

System.assertEquals(CRON_EXP, ct.CronExpression);
System.assertEquals(0, ct.TimesTriggered);
System.assertEquals('2022-03-15 00:00:00', String.valueOf(ct.NextFireTime));

Test.stopTest();
}
setting = Val_Rule_Cntrlr__c.getInstance(u.Id);

https://riptutorial.com/es/home 14
// check that the class did not change the All_Opportunity_Disabled__c field to false
System.assertEquals(true, setting.All_Opportunity_Disabled__c);
}

Lea Ajustes personalizados en línea: https://riptutorial.com/es/salesforce/topic/4927/ajustes-


personalizados

https://riptutorial.com/es/home 15
Capítulo 3: Apex Testing
Examples
Afirmar métodos

static TestMethod void DmlTest() {


List<Contact> allContacts = [SELECT Id FROM Contact];
System.assert(allContacts.isEmpty());

Contact testContact = new Contact(FirstName = 'John', LastName = 'Doe');


insert testContact;
allContacts = [SELECT Id FROM Contact];
System.assertNotEquals(0, allContacts.size(), 'Optional message in case of failure');

delete allContacts;
allContacts = [SELECT Id FROM Contact];
System.assertEquals(0, allContacts.size());
}

Clase de prueba basica

Esta clase de prueba IsBlank(...) el IsBlank(...) de SomeClass . A continuación se muestra el


ejemplo de SomeClass . Esta clase solo tiene un método static básico, pero no podrá
implementarlo en una instancia de producción para usarlo hasta que haya alcanzado el umbral de
cobertura del código.

public class SomeClass {

public static Boolean IsBlank(String someData) {


if (someData == null) {
return true;
} else if (someData == '') {
return true;
} else {
return false;
}
}

Como se puede ver, este método es simplemente una instrucción if con tres ramas. Para escribir
una clase de prueba efectiva, debemos cubrir cada rama con código y usar las
System.assertEquals(...) para verificar que se recibió la información correcta de IsBlank(...) .

@isTest
public class SomeClass_test {

@isTest
public static void SomeClass_IsBlank_test() {

https://riptutorial.com/es/home 16
String testData;

// SomeClass.IsBlank() returns true for Null values


System.assertEquals(true, SomeClass.IsBlank(testData));

testData = '';

// SomeClass.IsBlank() returns true for empty strings


System.assertEquals(true, SomeClass.IsBlank(testData));

testData = 'someData';

// SomeClass.IsBlank() returns false when testData is neither


// an empty string nor Null
System.assertEquals(false, SomeClass.IsBlank(testData));

Utilizando testSetup

Puede usar un método anotado con @testSetup para escribir el código que se habrá ejecutado
antes de cada ejecución de prueba:

public class AccountService {


public static Account fetchAccount() {
return [ SELECT Id, Name FROM Account LIMIT 1 ];
}
}

@isTest
public class AccountServiceTest {
private static final String TEST_ACCOUNT_NAME = 'My Test Account';

@testSetup
public static void setUpAccountData() {
Account a = new Account(Name = TEST_ACCOUNT_NAME);
}

@isTest
public static void testFetchAccount() {
Account a = AccountService.fetchAccount();
System.assertNotEquals(null, a, 'Account should not be null');
System.assertEquals(TEST_ACCOUNT_NAME, a.Name, 'Account name should be correct');
}
}

Utilizando bloques estáticos

Si bien puede usar la anotación @testSetup para designar un método que se ejecutará antes de
que se ejecuten las pruebas, este método generalmente solo se ejecutará una vez. Si necesita
que el código se ejecute antes de cada prueba, puede usar un bloque static :

@isTest

https://riptutorial.com/es/home 17
public class MyTest {
static {
// code here will be run before each test is executed
}
}

Metodos de afirmacion

System.assert se puede usar para verificar que una expresión booleana se evalúe como
verdadera:

System.assert(Service.isActive());
System.assert(!Service.getItems().isEmpty(), 'items should not be empty');

System.assertEquals y System.assertNotEquals se pueden usar para verificar la igualdad de dos


valores. El valor esperado se pasa como el primer parámetro, y el valor bajo prueba se pasa
como el segundo parámetro.

System.assertEquals(4, Service.getItems().size());
System.assertNotEquals(null, Service.getItems());

// failure messages are optional:


System.assertEquals(true, Service.doWork(), 'doWork should return true');
System.assertNotEquals(null, Service.doWork(), 'doWork should not be null');

Lea Apex Testing en línea: https://riptutorial.com/es/salesforce/topic/4930/apex-testing

https://riptutorial.com/es/home 18
Capítulo 4: Apex Triggers
Sintaxis
• desencadenar < nombre > en < nombre de api de objeto > (< eventos >) {// su lógica de
desencadenante}

Parámetros

parámetro descripción

nombre Nombre del disparador

nombre-api- Objeto sobre el que disparará el gatillo. Puede ser cualquier objeto estándar
objeto o personalizado.

Eventos que dispararán el gatillo. Son una combinación de before / after con
eventos cualquiera de insert / update / delete . También hay after undelete sin before
contraparte.

Examples
Disparador basico

trigger AccountTrigger on Account (before insert) {


System.debug('Account(s) are about to be inserted');
}

Variables de contexto de disparo

trigger ContactTrigger on Contact (before insert, after insert,


before update, after update,
before delete, after delete,
after undelete) {
/** Before or After trigger execution**/
//Returns true if trigger is before
System.debug('Trigger:Time:Before : ' + Trigger.isBefore);
//Returns true if trigger is after
System.debug('Trigger:Time:After : ' + Trigger.isAfter);

/**DML Operation trigger execution **/


//Returns true if trigger is insert
System.debug('Trigger:DML:Insert : ' + Trigger.isInsert);
//Returns true if trigger is update
System.debug('Trigger:DML:Update : ' + Trigger.isUpdate);
//Returns true if trigger is delete
System.debug('Trigger:DML:Delete : ' + Trigger.isDelete);

https://riptutorial.com/es/home 19
//Returns true if trigger is undelete
System.debug('Trigger:DML:Undelete: ' + Trigger.isUndelete);

/** Records on Trigger execution **/


//Returns data in state before DML. Records are read only
//Not available for Insert Operation
//Format: List<sObject>
List<Contact> old_contacts = Trigger.old;
System.debug('Trigger:Data:Old : ' + old_contacts);
//Returns data in state before DML. Records are read only
//Not available for Insert Operation
//Format: Map<Id, sObject>
Map<Id, Contact> old_contacts_map = Trigger.oldMap;
System.debug('Trigger:Data:OldMap : ' + old_contacts_map);
//Returns data in state after DML.
//Allowed for modifications in before context only
//Not available for Delete Operation
//Format: List<sObject>
List<Contact> new_contacts = Trigger.new;
System.debug('Trigger:Data:New : ' + new_contacts);
//Returns data in after before DML.
//Allowed for modifications in before context only
//Not available for InsertOperation
//Format: Map<Id, sObject>
Map<Id, Contact> new_contacts_map = Trigger.newMap;
System.debug('Trigger:Data:NewMap : ' + new_contacts_map);

/** Another context variables **/


//Returns amount of record in DML for trigger execution
System.debug('Trigger:Size :' + Trigger.size);
//Returns true if the current context for the Apex code
//is a trigger, not VF, web service or anonymous apex
System.debug('Trigger:isExecuting :' + Trigger.isExecuting);

//Simple example how to use above context variables


//for different scenarios in combination
if (Trigger.isBefore && Trigger.isUpdate) {
// actions for before update
} else if (Trigger.isAfter) {
if (Trigger.isUpdate) {
// actions for after update
} else if (Trigger.isInsert) {
// actions for after insert
}
}
}

Manipulando registros que dispararon el gatillo.

trigger MyTrigger on SomeObject__c (after insert, after update) {


if (Trigger.isAfter && Trigger.isInsert) {
System.debug('The following records were inserted: ');
for (SomeObject__c o : Trigger.new) {
System.debug(o.Name);
}
} else if (Trigger.isAfter && Trigger.isUpdate) {
for (Id key : Trigger.newMap) {
SomeObject__c theOldOne = Trigger.newMap.get(key);
SomeObject__c theNewOne = Trigger.oldMap.get(key);

https://riptutorial.com/es/home 20
if (theNewOne.Name != theOldOne.Name) {
System.debug('The name of ' + key + ' has been changed');
}
}
}
}

Lea Apex Triggers en línea: https://riptutorial.com/es/salesforce/topic/4864/apex-triggers

https://riptutorial.com/es/home 21
Capítulo 5: API REST de Salesforce
Introducción
Force.com Documentación API REST. La lista completa de API's está aquí.

Examples
OAuth2 access_token y lista de servicios

Para obtener el token de acceso OAuth2 simplemente haga


curl https://login.salesforce.com/services/oauth2/token -d "grant_type=password" -d
"client_id=myclientid" -d "client_secret=myclientsecret" -d "username=mylogin@salesforce.com" -d
"password=mypassword123456"

Debe obtener respuesta algo como

{
"access_token":
"00D6F0xxx001g1qs!ARsAQL7BRiQQ0lgTW7zXu3kILJBxxxxxHvDnChF2ETBFJpX0T2LsBsm8MVABhAvINAyZqgDIAHhJDp6QjuF6Z

"instance_url": "https://ap4.salesforce.com",
"id": "https://login.salesforce.com/id/00D6F000001xxxxAA/0056F000006DMcxxxx",
"token_type": "Bearer",
"issued_at": "14878401xxxxx",
"signature": "Ra5Sdm6gq4xxxeZYk3H2yBIVpZ6hBUDgkQ4Tjp9Q="
}

Entonces hazlo

{
"tooling": "/services/data/v20.0/tooling",
"eclair": "/services/data/v20.0/eclair",
"prechatForms": "/services/data/v20.0/prechatForms",
"async-queries": "/services/data/v20.0/async-queries",
"query": "/services/data/v20.0/query",
"chatter": "/services/data/v20.0/chatter",
"wave": "/services/data/v20.0/wave",
"search": "/services/data/v20.0/search",
"identity": "https://login.salesforce.com/id/00D6F000001g1qsUAA/0056F000006DMcMQAW",
"sobjects": "/services/data/v20.0/sobjects",
"serviceTemplates": "/services/data/v20.0/serviceTemplates",
"recent": "/services/data/v20.0/recent",
"connect": "/services/data/v20.0/connect",
"licensing": "/services/data/v20.0/licensing"
}

Lea API REST de Salesforce en línea: https://riptutorial.com/es/salesforce/topic/9210/api-rest-de-


salesforce

https://riptutorial.com/es/home 22
Capítulo 6: Bulkificación del gatillo
Examples
Bulkificación

Si realiza el procesamiento fila por fila en Salesforce, probablemente alcanzará el límite del
gobernador rápidamente. Esto es especialmente cierto con los factores desencadenantes y las
cosas que se activan cuando no los espera. Un método documentado de escapar del límite del
gobernador es la masificación.

Nota: la siguiente información se basa en los documentos oficiales de Salesforce.

Acumular el código de Apex significa asegurarse de que el código maneja correctamente más de
un registro a la vez. Cuando un lote de registros inicia Apex, se ejecuta una sola instancia de ese
código de Apex, pero esa instancia necesita manejar todos los registros en ese lote dado.

No Bulkified:

trigger accountTestTrggr on Account (before insert, before update)


{

//This only handles the first record in the Trigger.new collection


//But if more than 1 Account initiated this trigger, those additional records
//will not be processed
Account acct = Trigger.new[0];
List<Contact> contacts = [select id, salutation, firstname, lastname, email
from Contact where accountId =&nbsp;:acct.Id];

Bulkified:

trigger accountTestTrggr on Account (before insert, before update)


{
List<String> accountNames = new List<String>{};
//Loop through all records in the Trigger.new collection
for(Account a: Trigger.new){
//Concatenate the Name and billingState into the Description field
a.Description = a.Name + ':' + a.BillingState
}
}

Lea Bulkificación del gatillo en línea: https://riptutorial.com/es/salesforce/topic/4272/bulkificacion-


del-gatillo

https://riptutorial.com/es/home 23
Capítulo 7: Desarrollo de la página de
Visualforce
Examples
Pagina basica

Una página básica de VisualForce se puede crear así:

<apex:page>
<h1>Hello, world!</h1>
</apex:page>

Uso de controladores estándar

Si su página es para mostrar o editar información sobre un tipo particular de registro, puede ser
útil usar un controlador estándar para reducir la cantidad de código de boiler que necesita escribir.

Al usar un controlador estándar, su página se mostrará con un parámetro ?id=SALESFORCE_ID , y


obtendrá acceso automáticamente a todos los campos de combinación en el registro.

Agregue un controlador estándar a su página especificando el atributo controlador


standardController en <apex:page> :

<apex:page standardController="Account">
This is a page for {!Account.Name}
</apex:page>

También obtienes los métodos de control estándar gratis:

• cancel() : devuelve la PageReference para la página de cancelación (por lo general, vuelve a


la vista de lista)
• delete() : elimina el registro y devuelve la PageReference de página para la página de
eliminación
• edit() - devuelve la PageReference para la página de edición estándar
• save() : guarda el registro y devuelve la PageReference de PageReference al registro actualizado
• view() - devuelve la PageReference para la página de vista estándar

Puedes usarlos así:

<apex:page standardController="Account">
Name: <apex:inputField value="{!Account.Name}" />
<apex:commandButton value="Update record" action="{!save}" />
</apex:page>

Lea Desarrollo de la página de Visualforce en línea:

https://riptutorial.com/es/home 24
https://riptutorial.com/es/salesforce/topic/6372/desarrollo-de-la-pagina-de-visualforce

https://riptutorial.com/es/home 25
Capítulo 8: Herramientas para el desarrollo
Examples
IDEs

Una lista de IDE disponibles para crear clases, desencadenadores, páginas / componentes de
Visualforce / Lightning.

• Force.com IDE - plugin para Eclipse


• JedIDE : complemento para IntelliJ IDEA y el IDE de Force.com independiente
• MavensMate - plugin para Sublime Text y Atom y VS Code
• FuseIT SFDC Explorer : esta es una herramienta independiente
• Welkin Suite - Esta es una herramienta independiente;
• Nube iluminada - plugin para IntelliJ IDE
• Aside.io - IDE basado en web
• Cloud 9 - IDE basado en web
• VimAwesome - Complemento VIM para Force.com
• HaoIDE - Complemento de texto sublime para Force.com
• Metaforce : una aplicación ligera de Chrome para el desarrollo de Salesforce

Extensiones de navegador

• Salesforce Navigator ( Google Chrome )


• Force.com Inicios de sesión ( Google Chrome , Firefox )
• Salesforce Developer Tool Suite ( Google Chrome )
• Salesforce Lighting Components Inspector ( Google Chrome )
• Salesforce Developer Tool Suite ( Google Chrome )
• Expansor de esquemas de Salesforce ( Google Chrome )
• Boostr para Salesforce ( Google Chrome )
• Nombres de la API de Salesforce ( GoogleChrome )
• Changeset Helper ( Google Chrome )
• Salesforce Inspector ( Google Chrome , Firefox )
• Salesforce Mass Editor ( Google Chrome )
• Espacio ( Google Chrome )

Depuradores

• Depurador oficial de Apex

○ Depuración en tiempo real


○ IDE de Force.com
○ requiere licencia especial de salesforce

• Traje welkin

https://riptutorial.com/es/home 26
○ Registro de depuración de depuración
○ IDE independiente
○ Se requiere suscripción

• Nube Iluminada :

○ Registro de depuración de depuración


○ Extensión de JetBrains
○ Se requiere suscripción

• Salesforce Apex Debug

○ Registro de depuración de depuración


○ Extensión de Código VS
○ Libre y de código abierto.
○ Actualmente todavía en alfa

Herramientas de Salesforce ETL

• Salesforce DataLoader
• Dataloader.io
• Jitterbit
• SFXOrgData
• DreamFactory Monarch
• Pentaho Tetera
• Talend

Herramientas de análisis estático

• CodeClimate : Servicio en la nube


• CodeScan : Servicio en la nube
• Clayton.io : Servicio en la nube
• VSCode Apex PMD : extensión de código VS para análisis estático en tiempo real a medida
que codifica
• Apex PMD : núcleo de línea de comando que ejecuta la mayoría de las herramientas
anteriores

Lea Herramientas para el desarrollo en línea:


https://riptutorial.com/es/salesforce/topic/4095/herramientas-para-el-desarrollo

https://riptutorial.com/es/home 27
Capítulo 9: Lenguaje de consulta de objetos
de Salesforce (SOQL)
Sintaxis
• SELECCIONAR ID DE Cuenta
• SELECCIONAR ID, Nombre DESDE cuenta
• SELECCIONE ID DE LA Cuenta DONDE Nombre = 'SomeAccountName'
• SELECCIONE ID, Nombre, (SELECCIONE ID, Nombre DE Contactos) DESDE Cuenta
• SELECCIONE ID, nombre DESDE la cuenta DONDE Id =: apexVariableName

Examples
Consulta SOQL básica

SELECT Id, Name FROM Account

Esto devolverá los campos Id y Nombre de la tabla de la Cuenta. No se aplicará ningún filtrado o
clasificación.

Consulta SOQL Con Filtrado

SELECT Name FROM User WHERE IsActive = true

Esto devolverá el nombre de todos los usuarios activos.

SELECT Name, Phone FROM Contact WHERE CreatedDate >= 2016-01-01T00:00:00.000Z

Esto devolverá los contactos creados el 1 de enero de 2016 o después.

SELECT Id, Name FROM Account LIMIT 100

Esto devolverá las primeras 100 cuentas de una lista no ordenada.

SELECT Id, Name, Phone FROM Lead WHERE Phone LIKE '(%) %-%'

Esto devolverá Leads con un número de teléfono que coincida con el formato especificado. "%"
actúa como un carácter comodín.

Usar LIKE '% %' también permite que un desarrollador replique una fórmula CONTAINS( ) .

SELECT Email FROM Lead WHERE LeadSource LIKE '%Google%'

https://riptutorial.com/es/home 28
Devolverá los prospectos con una fuente principal que contenga Google, es decir, "AdWords de
Google" y "Búsqueda natural de Google".

Consulta de SOQL con pedidos

SELECT Id, Name FROM User ORDER BY LastName

SELECT Id, Name FROM Contact ORDER BY LastModifiedDate DESC

SELECT Name, Title FROM User ORDER BY Title ASC NULLS FIRST

SELECT Id FROM Contact ORDER BY LastName ASC NULLS LAST, FirstName ASC NULLS FIRST

Usando SOQL para construir un mapa

Una característica muy útil que muchas personas pasan por alto es la capacidad de construir un
mapa usando una consulta SOQL.

Map<Id, Account> accounts = new Map<Id, Account>([SELECT Id, Name FROM Account]);
System.debug(accounts);

Cuando ejecuta este código, las accounts contienen un mapa de los objetos de su cuenta, con la
clave de identificación. La salida al registro de depuración se vería similar a esto:

11:15:10:025 USER_DEBUG [13]|DEBUG|{


XXXXXXXXXXXXXXXXXX=Account:{Id=XXXXXXXXXXXXXXXXXX, Name=Account 1},
YYYYYYYYYYYYYYYYYY=Account:{Id=YYYYYYYYYYYYYYYYYY, Name=Account 2},
ZZZZZZZZZZZZZZZZZZ=Account:{Id=ZZZZZZZZZZZZZZZZZZ, Name=Account 3},
...
}

Ahora puede buscar los objetos de la Cuenta utilizando su Id. Además, si desea una colección de
ID únicas, puede llamar a la función keySet() de la clase Map, así:

System.debug(accounts.keySet());

que se ve algo como esto en el registro de depuración:

11:23:21:010 USER_DEBUG [15]|DEBUG|{XXXXXXXXXXXXXXXXXX, YYYYYYYYYYYYYYYYYY,


ZZZZZZZZZZZZZZZZZZ, ...}

Esto es muy útil cuando necesita consultar para obtener registros y acceder a ellos repetidamente
en su código.

Consulta de SOQL para hacer referencia a los campos del objeto principal

Cuando los objetos están vinculados por una relación de búsqueda o detalle maestro, los campos
de registros primarios pueden ser referenciados desde el registro secundario o "objeto base" en
una consulta. Esto también se conoce como travesía hacia arriba.

https://riptutorial.com/es/home 29
SELECT FirstName, Account.Name, Account.Category__c FROM Contact

Es posible recorrer cinco récords hacia arriba.

SELECT Account.Owner.Profile.CreatedBy.Name FROM Contact

Cuando el objeto base es un campo de búsqueda personalizado, el __c en el nombre del campo
Primary_Influencer__c, por ejemplo, se cambiará a __r.

SELECT Primary_Influencer__r.Nickname__c FROM Contact

Consulta SOQL para obtener registros hijo

SELECT Id, Name, (SELECT Id, FirstName, LastName FROM Contacts) FROM Account

Consultas SOQL en Apex

Para realizar una consulta en Apex, rodee la consulta entre corchetes. El resultado se puede
asignar a una lista, o a un solo objeto.

List<Account> allAccounts = [SELECT Id, Name FROM Account];


Account oldestAccount = [SELECT Id, Name FROM Account ORDER BY CreatedDate LIMIT 1];

Referencias de variables en las consultas de Apex SOQL

Para hacer referencia a una variable en una consulta, agregue dos puntos (:) antes del nombre de
la variable.

Datetime targetDate = Datetime.now().addDays(-7);


List<Lead> recentLeads = [SELECT Id FROM Lead WHERE CreatedDate > :targetDate];

string targetName = 'Unknown';


List<Contact> incompleteContacts = [SELECT Id FROM Contact WHERE FirstName = :targetName];

Posibles excepciones en las consultas de Apex SOQL

Cuando se asigna a un solo objeto, una consulta que devuelve algo que no sea una sola fila
arrojará una QueryException .

try {
Account a = [SELECT Id FROM Account WHERE Name = 'Non-existent Account'];
} catch (QueryException e) {
// List has no rows for assignment to SObject
}

try {
Account a = [SELECT Id FROM Account];
} catch (QueryException e) {
// List has more than 1 row for assignment to SObject

https://riptutorial.com/es/home 30
}

Si intenta utilizar un campo que no incluyó en la consulta, se emitirá una SObjectException

Account a = [SELECT Id FROM Account LIMIT 1];


try {
System.debug( a.Name );
} catch (SObjectException e) {
// SObject row was retrieved via SOQL without querying the requested field: Name
}

Usando un Semi-Join

Seleccionar todas las cuentas que tienen registros de oportunidades abiertas debajo de ellas

SELECT Id, Name FROM Account WHERE AccountId IN


(SELECT Id FROM Opportunity WHERE IsClosed = false)

SOQL dinámico

Puede ejecutar una consulta de base de datos desde una cadena en lugar de una expresión
SOQL regular:

String tableName = 'Account';


String queryString = 'SELECT Id FROM ' + tableName + ' WHERE CreatedDate >= YESTERDAY';
List<SObject> objects = Database.query(queryString);

Dado que las consultas dinámicas de SOQL no se compilan, sus referencias de esquema no se
validan, por lo que es preferible utilizar la interpolación de variables de Apex utilizando la sintaxis
:variable cuando sea posible.

Lea Lenguaje de consulta de objetos de Salesforce (SOQL) en línea:


https://riptutorial.com/es/salesforce/topic/4217/lenguaje-de-consulta-de-objetos-de-salesforce--
soql-

https://riptutorial.com/es/home 31
Capítulo 10: Manipulación de fecha y hora
Examples
Encuentra fácilmente el último día de un mes

Si necesita encontrar el último día del mes, puede hacer gimnasia complicada con DateTime o
puede usar el siguiente método.

Digamos que quieres encontrar el último día de febrero de 2021. Haz lo siguiente:

Integer month = 2;
Integer day = null;
Integer year = 2021;

// Create a new DateTime object for the first day of the month following
// the date you're looking for.
DateTime dtTarget = DateTime.newInstance(year, month, 1);
//In this case we would be sure that month would not be out of bound
dtTarget = dtTarget.addMonths(1);
// Then use the .addDays() method to add negative 1 days. This gives you
// the last day of the target month.
DateTime lastDayOfMonth = dtTarget.addDays(-1);
day = lastDayOfMonth.day();

System.debug(lastDayOfMonth);
System.debug(day);

Esto produce el siguiente resultado en los registros:

18:19:57:005 USER_DEBUG [15]|DEBUG|2021-02-28 08:00:00


18:21:10:003 USER_DEBUG [16]|DEBUG|28

Esto funciona para todos los métodos de adición, lo que le permite encontrar DateTimes de forma
fácil y rápida en el pasado.

Lea Manipulación de fecha y hora en línea:


https://riptutorial.com/es/salesforce/topic/4928/manipulacion-de-fecha-y-hora

https://riptutorial.com/es/home 32
Capítulo 11: Navegación de la página con la
ayuda de la clase envoltura de lista en la
fuerza de ventas.
Introducción
Slaesforce StandardSetController solo mantiene la lista de sObject, no contiene la lista de objetos
de la clase contenedora. A continuación, el código fuente muestra el uso de Paginating utilizando
Wrapper Class en sales-force.

Examples
Controlador de paginación

Ejemplo de código: ahora comience con la creación del controlador de paginación

public with sharing class Pagination {

Voy a mostrar todos los contactos en forma de paginación y debería haber una casilla de
verificación para cada contacto a seleccionar o deseleccionar contacto para realizar una
operación de eliminación en los contactos. Así que necesito crear una clase de contenedor para
mantener el contacto y la variable booleana para la selección. Primero cree la clase Wrapper para
el controlador Paginación Inserte debajo del código en el controlador de paginación.

public class contactWrapper{


public Contact cont {get;set;}
public Boolean isSelected{get;set;}
public contactWrapper(contact c,Boolean s)
{
cont=c;
isSelected=s;
}
}

Ahora recuperando datos en Apex to Paginate con la ayuda de StandardSetController. El


StandardSetController es una herramienta extremadamente poderosa con una funcionalidad
incorporada que puede utilizar para simplificar enormemente el código personalizado en sus
páginas de Visualforce. Debido a que el servidor solo devuelve los datos para la página solicitada,
el StandardSetController puede reducir significativamente el estado de vista, especialmente en
comparación con el estado de vista que obtendría al usar SOQL.

Public Integer noOfRecords{get; set;} // Future reference in Visual force Page


Public Integer size{get;set;} // Future reference in Visual force Page

https://riptutorial.com/es/home 33
public final Integer Page_Size=10; // Number records in a Page should be displayed

public ApexPages.StandardSetController setCon {


get{
if(setCon == null){
size=Page_Size;
string queryString = 'Select Id,Name, Email, Birthdate, Phone, MobilePhone
from Contact order by Name';
setCon = new
ApexPages.StandardSetController(Database.getQueryLocator(queryString));
setCon.setPageSize(size);
noOfRecords = setCon.getResultSize();
}
return setCon;
}set;
}

Ahora tiene los contactos en la variable setCon, siempre que solicite setCon.getRecords (),
recuperará los primeros 10 registros de contacto de la setCon. Aquí tengo crear una clase
envoltura simple para mostrarle la demostración. Puede crear su propia clase de envoltura según
el requisito. Pero siempre debe tener en cuenta que ApexPages.StandardSetController contiene
solo la Lista de sObject, no contendrá la lista de objetos de la clase de contenedor. Esa es la
razón por la que he escrito un código adicional a continuación para lograr este futuro de manera
diferente. A continuación, el código convierte la lista de contactos en una lista de objetos de la
clase envoltura, de modo que, cuando llame a los contactos en la página de fuerza visual, recibirá
la lista de objetos de la clase envoltura.

public list<contactWrapper> contWpr{get;set;}


public set<id> selectedContactIds{ get;private set;} // to maintain state of the selected
contact
// through out paginating

public Pagination() {
selectedContactIds=new set<id>();
}

Public list<contactWrapper> getContacts(){


contWpr =new list<contactWrapper>();
for(Contact c: (List<Contact>)setCon.getRecords())
if(selectedContactIds.contains(c.id))
contWpr.add(new contactWrapper(c,true));
else
contWpr.add(new contactWrapper(c,false));
return contWpr;
}

Ahora ha escrito un código para generar resultados. ¿Pero cómo navegar por la página? Esto se
puede hacer con un paso sencillo con ApexPages.StandardSetController. Mire la siguiente
belleza del código del StandardSetController, No es necesario mantener el número de página, el
desplazamiento y el límite, etc. Solo use los métodos del StandardSetController. Copie el
siguiente código en el controlador de paginación.

public Boolean hasNext {


get {
return setCon.getHasNext();

https://riptutorial.com/es/home 34
}
set;
}
public Boolean hasPrevious {
get {
return setCon.getHasPrevious();
}
set;
}

public Integer pageNumber {


get {
return setCon.getPageNumber();
}
set;
}

public void first() {


setCon.first();
// do you operation here
}

public void last() {


setCon.last();
// do you operation here
}

public void previous() {


setCon.previous();
// do you operation here
}

public void next() {


setCon.next();
// do you operation here
}

Ya casi terminas con Paginar los contactos. Últimos pocos métodos que he agregado para
cumplir con toda la funcionalidad de mi página. Como mencioné anteriormente, tenemos una
casilla de verificación adicional para seleccionar un contacto y realizar una operación de
eliminación en los contactos seleccionados.

public void contactSelection()


{
Id id=(Id)ApexPages.currentPage().getParameters().get('cId');
if(selectedContactIds.contains(id))
selectedContactIds.remove(id);
else
selectedContactIds.add(id);
}

public void deleteContacts()


{
List<contact> contactToDelete=[select id from contact where id in
:selectedContactIds];
if(contactToDelete.size()!=0) // if(!contactToDelete.isEmpty()) // Best Practice
{
try { delete contactToDelete; } // You may get Exception if you try to
delete the

https://riptutorial.com/es/home 35
// related contact ,include try block to avoid
error.
catch(exception ex){ System.debug(ex); }
refresh();
}
}

public pageReference refresh() {


setCon = null;
selectedContactIds=new set<id>();
getContacts();
setCon.setPageNumber(1);
return null;
}

Lea Navegación de la página con la ayuda de la clase envoltura de lista en la fuerza de ventas. en
línea: https://riptutorial.com/es/salesforce/topic/10744/navegacion-de-la-pagina-con-la-ayuda-de-
la-clase-envoltura-de-lista-en-la-fuerza-de-ventas-

https://riptutorial.com/es/home 36
Capítulo 12: Procesos de aprobación de
objetos
Observaciones
El Proceso de aprobación es una característica muy sorprendente en Salesforce para automatizar
el proceso de negocios. Un proceso de aprobación es un conjunto de los pasos necesarios para
que un aprobador o un conjunto de aprobadores aprueben o rechacen un registro en particular.

Un paso puede aplicarse a todos los registros incluidos en el proceso, o solo a registros que
cumplan con ciertos criterios definidos por el administrador. Un proceso de aprobación también
especifica las acciones a tomar cuando un registro se aprueba, rechaza, recupera o envía por
primera vez para su aprobación.

Los objetos ProcessDefinition y ProcessNode actúan como una plantilla y almacenan


las configuraciones maestras para el propio Proceso de aprobación.

https://riptutorial.com/es/home 37
Examples
ProcesoDefinición

Representa la definición de un proceso de aprobación único. Utilice este objeto para leer la
descripción de un proceso de aprobación. La definición es de solo lectura. No podemos modificar
el registro creado en ProcessDefinition Object. Pero podemos describir, consultar, buscar y
recuperar la información de los procesos de aprobación.

~ Consulta ~

SELECT CreatedById,CreatedDate,Description,DeveloperName,LastModifiedById,
LastModifiedDate,LockType,Name,State,SystemModstamp,TableEnumOrId,Type,Id

https://riptutorial.com/es/home 38
FROM ProcessDefinition

Los registros se crean cuando creamos un nuevo proceso de aprobación utilizando la interfaz de
usuario de Salesforce del Proceso de aprobación.

ProcessNode

Representa los pasos de proceso creados para un proceso de aprobación particular


(ProcessDefinition). Este objeto se utiliza para leer la descripción del paso del proceso. En
palabras simples, los registros de ProcessNode describen un paso en una definición de proceso.
Podemos describir, consultar, buscar y recuperar los pasos de los procesos de aprobación.

~ Consulta ~

SELECT Description,DeveloperName,Name,ProcessDefinitionId,SystemModstamp
,Id,FROM ProcessNode

Como podemos ver, el campo ProcessDefinitionId actúa como una clave externa que se refiere al
objeto o tabla ProcessDefinition para los pasos o nodos de proceso que se crean. Este objeto
también se lee solo como objeto ProcessDefinition.

ProcessInstance

Representa una instancia de un solo proceso de aprobación completo. El registro


ProcessInstance se crea cada vez para un registro de objeto particular que se envía para su
aprobación. También es un objeto de sólo lectura. Podemos describir, consultar y recuperar los
procesos de aprobación de Instancia.

~ Consulta ~

SELECT CompletedDate,CreatedById,CreatedDate,ElapsedTimeInDays,
ElapsedTimeInHours,ElapsedTimeInMinutes,Id,IsDeleted,LastActorId,
LastModifiedById,LastModifiedDate,ProcessDefinitionId,Status,
SubmittedById,SystemModstamp,TargetObjectId FROM ProcessInstance

Todos los campos ProcessInstance se rellenan automáticamente una vez que el registro se envía
para su aprobación, con dos campos de excepciones: CompletedDate y LastActorId que se
completan solo después de que se completa la instancia del proceso de aprobación. El campo
ProcessDefinitionId es el ID de referencia o clave externa del objeto ProcessDefinition.

ProcessInstanceStep & ProcessInstanceWorkitem

Ambos objetos ProcessInstanceStep y ProcessInstanceWorkItem son instancias de pasos de


proceso que se crean para ProcessInstance en particular. ProcessInstanceStep representa una
instancia de paso en un proceso de aprobación (ProcessInstance) en el que los usuarios ya han
actuado y ProcessInstanceWorkItem representa una instancia de paso en un proceso de
aprobación (ProcessInstance) en el que está pendiente y los usuarios deben realizar alguna
acción a continuación. Podemos describir, consultar y recuperar los pasos de los procesos de

https://riptutorial.com/es/home 39
aprobación y los elementos de trabajo.

~ Consulta ~

SELECT CreatedById,CreatedDate,ElapsedTimeInDays,ElapsedTimeInHours,
ElapsedTimeInMinutes,Id,IsDeleted,OriginalActorId,ProcessInstanceId,
ActorId,SystemModstamp FROM ProcessInstanceWorkitem

SELECT ActorId,Comments,CreatedById,CreatedDate,ElapsedTimeInDays,Id,
ElapsedTimeInHours,ElapsedTimeInMinutes,OriginalActorId,ProcessInstanceId
,StepNodeId,StepStatus,SystemModstamp FROM ProcessInstanceStep

ProcessInstanceHistory *

ProcessInstanceHistory es el objeto que no se puede buscar ni consultar. Este es el objeto de


solo lectura que muestra todos los pasos y solicitudes de aprobación pendientes asociadas con
un proceso de aprobación (ProcessInstance). Pero podemos usar este objeto para replicar la
funcionalidad de lista relacionada de la interfaz de usuario de Salesforce para los procesos de
aprobación que se mostrarán en mi próxima publicación de blog pronto. Podemos usar
ProcessInstanceHistory para una sola vista de solo lectura de los objetos ProcessInstanceStep y
ProcessInstanceWorkitem. Podemos consultar ProcessInstanceHistory consultando en una
consulta soql anidada en el objeto ProcessInstance principal. La consulta de soql anidada hace
referencia a StepsAndWorkitems , que es el nombre de la relación secundaria para
ProcessInstanceHistory en el objeto ProcessInstance. Este es un objeto muy útil para resolver
diversos problemas de negocios.

~ Consulta ~

SELECT CompletedDate, CreatedById, CreatedDate,Id,IsDeleted,LastActorId,


LastModifiedById,LastModifiedDate,ProcessDefinitionId,Status,SubmittedById
,SystemModstamp,TargetObjectId, (SELECT ID, ProcessNodeId, StepStatus,
Comments,TargetObjectId,ActorId,CreatedById,IsDeleted,IsPending,
OriginalActorId,ProcessInstanceId,RemindersSent,CreatedDate
FROM StepsAndWorkitems ) FROM ProcessInstance

Lea Procesos de aprobación de objetos en línea:


https://riptutorial.com/es/salesforce/topic/6387/procesos-de-aprobacion-de-objetos

https://riptutorial.com/es/home 40
Capítulo 13: SalesForce Integración CI
Introducción
Lugar para usar Jenkins y Sonar para CI

Examples
¿Cómo configurar Jenkins para implementar código en desarrollo o
producción org?

Cómo podemos usar jenkins en nuestro desarrollo de productos SalesForce. ¿Cuáles son los
complementos de herramientas disponibles para la integración de Jenkins? ¿Cómo resolver el
problema de configuración de CI? Etc.

Herramientas Jenkins CI que se pueden utilizar para la automatización de


SalesForce

1. Jenkins : el servidor de automatización de código abierto líder, Jenkins proporciona cientos


de complementos para ayudar a construir, implementar y automatizar cualquier proyecto.
2. Sonar Qube : SonarQube proporciona la capacidad no solo de mostrar la salud de una
aplicación, sino también de resaltar los problemas recientemente presentados.
3. Apache Ant : Apache Ant es una herramienta de línea de comandos y biblioteca de Java
cuya misión es impulsar los procesos descritos en los archivos de compilación como
destinos y puntos de extensión que dependen unos de otros.
4. Apache Maven : Apache Maven es una herramienta de gestión y comprensión de proyectos
de software. Basándose en el concepto de un modelo de objeto de proyecto (POM), Maven
puede gestionar la compilación, los informes y la documentación de un proyecto a partir de
una información central.
5. SfApexDoc : Soporte para JavaDoc como herramienta de creación de documentación.
Puede ser utilizado por Ant / Jenkins para crear Documentos.
6. Informe de formato JUnit para APEX : amplía Force.com com.salesforce.ant.DeployTask
para aceptar un argumento opcional junitreportdir que define la carpeta en la que se genera
un archivo XML JUnitReport. Este archivo puede ser consumido directamente por la
herramienta de integración continua de Jenkins para producir gráficos de tendencias y
detalles de resultados de prueba o por la tarea Ant de JUnitReport.
7. Sistema de control de versiones: puede usar GIT , SVN o cualquier otro sistema de control
de versiones
8. PMD Apex : contiene la implementación de PMD para admitir el lenguaje de programación
Apex.
9. Sonar para Apex (enforce-sonarqube-plugin) : el complemento es compatible con la
gramática del lenguaje Apex; la lista actual de comprobaciones se centra principalmente en
los componentes de prueba. El soporte para más componentes de SFDC está en progreso.

https://riptutorial.com/es/home 41
Lea SalesForce Integración CI en línea:
https://riptutorial.com/es/salesforce/topic/10044/salesforce-integracion-ci

https://riptutorial.com/es/home 42
Capítulo 14: Trabajando con Sistemas
Externos
Examples
Hacer una llamada saliente

Este es un ejemplo de cómo llamar a un servicio web de salesforce. El siguiente código está
llamando a un servicio basado en REST alojado en data.gov para encontrar mercados de
agricultores cerca del código postal.

Recuerde que para invocar una llamada HTTP de su organización, debe modificar la
configuración remota de la organización.

string url= 'http://search.ams.usda.gov/farmersmarkets/v1/data.svc/zipSearch?zip=10017';


Http h = new Http();
HttpRequest req = new HttpRequest();
HttpResponse res = new HttpResponse();
req.setEndpoint(url);
req.setMethod('GET');
res = h.send(req);
System.Debug('response body '+res.getBody());

Lea Trabajando con Sistemas Externos en línea:


https://riptutorial.com/es/salesforce/topic/4926/trabajando-con-sistemas-externos

https://riptutorial.com/es/home 43
Capítulo 15: Variables globales en las clases
Introducción
En este tema me gustaría mencionar todas las posibles variables globales que se pueden usar en
el código Apex. Me gusta [UserInfo Class] [1]. Sugiero que simplemente listemos clases /
variables globales y enlaces. Si conoce una clase / variable global pero no puede encontrar una
documentación, proporcione la mayor cantidad de información posible. [1]:
https://developer.salesforce.com/docs/atlas.en-
us.apexcode.meta/apexcode/apex_methods_system_userinfo.htm

Examples
Información de usuario

getFirstName () : devuelve el nombre del usuario del contexto.


getLastName () : devuelve el apellido del usuario del contexto.

Lea Variables globales en las clases en línea:


https://riptutorial.com/es/salesforce/topic/8174/variables-globales-en-las-clases

https://riptutorial.com/es/home 44
Capítulo 16: Variables globales en las
páginas de Visualforce
Examples
$ Recurso

Utilice la variable $Resource para hacer referencia a recursos estáticos.

<img src="{!$Resource.myImage}" />

Se puede usar junto con la función URLFOR para hacer referencia a archivos dentro de un recurso
estático comprimido:

<apex:includeScript value="{!URLFOR($Resource.myResources, 'js/app.js')}" />

$ Etiqueta

La variable $Label se puede usar para mostrar el texto definido en sus etiquetas personalizadas.

<apex:outputText value="{!$Label.Welcome_Message}" />

También puedes hacer formateo con etiquetas. Supongamos que tiene una etiqueta
personalizada llamada Welcome_Message definida como

Welcome to our site, {0}!

Podría usar la etiqueta para mostrar un mensaje con formato:

<apex:outputText value="{!$Label.Welcome_Message}"
rendered="{!NOT(ISBLANK($User.ContactId))}">
<apex:param value="{!$User.Contact.FirstName}" />
</apex:outputText>

$ Usuario

La variable $User le da acceso a todos los campos estándar y personalizados en el objeto User
para el usuario que ha iniciado sesión actualmente.

You are logged in as a user from {!$User.CompanyName}.

Lea Variables globales en las páginas de Visualforce en línea:


https://riptutorial.com/es/salesforce/topic/5184/variables-globales-en-las-paginas-de-visualforce

https://riptutorial.com/es/home 45
Creditos
S.
Capítulos Contributors
No

Empezando con
1 abhi, Alex S, Andrii Muzychuk, Ashwani, Community, Reshma
Salesforce

Ajustes
2 Alex S
personalizados

3 Apex Testing Andree Wille, battery.cord, Ben, Eric Dobbs

4 Apex Triggers kurunve, Pedro Otero

API REST de
5 radbrawler
Salesforce

Bulkificación del
6 abhi, hillary.fraley, LDP
gatillo

Desarrollo de la
7 página de Ben
Visualforce

abhi, Andrii Muzychuk, Daniel Ballinger, Force2b, Gres, hleb not


Herramientas para el
8 bread, itzmukeshy7, Mahmood, NSjonas, Pavel Slepiankou,
desarrollo
pchittum, Ratan Paul, sorenkrabbe, wintermute

Lenguaje de
consulta de objetos abhi, Alex S, Andrii Muzychuk, battery.cord, Ben, ca_peterson,
9
de Salesforce Doug B, Eric Dobbs, LDP, Ratan Paul
(SOQL)

Manipulación de
10 kurunve, LDP, RamenChef
fecha y hora

Navegación de la
página con la ayuda
11 de la clase envoltura NITHESH K
de lista en la fuerza
de ventas.

Procesos de
12 aprobación de Ajay Gupta
objetos

https://riptutorial.com/es/home 46
SalesForce
13 Sanjay Kharwar
Integración CI

Trabajando con
14 abhi, mnoronha
Sistemas Externos

Variables globales
15 Andrii Muzychuk
en las clases

Variables globales
16 en las páginas de Ben
Visualforce

https://riptutorial.com/es/home 47

También podría gustarte