馃З ¿Qu茅 incluye esta plantilla?
-
Apex Controller (CitaController)
-
obtenerClientes(): Lista cuentas (clientes)
-
consultarDisponibilidad(): Simula horarios disponibles
-
sugerirCitaConEinstein(): Simula sugerencia de cita usando Einstein GPT
-
Flow sugerido (no-code):
-
Crea un registro de Cita__c
-
Usa clienteId y fechaHora
-
Puedes a帽adir notificaci贸n por correo o Slack
Apex Controller (CitaController)
-
obtenerClientes(): Lista cuentas (clientes) -
consultarDisponibilidad(): Simula horarios disponibles -
sugerirCitaConEinstein(): Simula sugerencia de cita usando Einstein GPT
Flow sugerido (no-code):
-
Crea un registro de Cita__c
-
Usa
clienteIdyfechaHora -
Puedes a帽adir notificaci贸n por correo o Slack
✅ Pr贸ximos pasos:
-
Crear un componente LWC que consuma este controller
-
Crear un Flow llamado Guardar Cita que cree el registro
-
Si tienes Einstein GPT habilitado, puedes reemplazar la funci贸n simulada por un prompt real
-
Opcional: A帽adir conexi贸n real a una API externa usando Named Credential
Proyecto Gestor Citas Salesforce✅ He a帽adido el componente LWC base (gestorCitas) a tu plantilla.
Con esto ya tienes:
Apex Controller (CitaController) para clientes, disponibilidad y sugerencia.
LWC (gestorCitas.html y gestorCitas.js) que muestra clientes, consulta disponibilidad y obtiene una sugerencia simulada de Einstein.
Flow sugerido para guardar la cita.
Archivo
// ApexController.cls
public with sharing class CitaController {
@AuraEnabled(cacheable=true)
public static List<Account> obtenerClientes() {
return [SELECT Id, Name FROM Account LIMIT 50];
}
@AuraEnabled
public static String consultarDisponibilidad(String clientId) {
// Simulaci贸n de consulta a una API externa
List<String> horarios = new List<String>{'10:00 AM', '11:30 AM', '3:00 PM'};
return 'Disponible en: ' + String.join(horarios, ', ');
}
@AuraEnabled
public static String sugerirCitaConEinstein(String nombreCliente) {
// Simulaci贸n de sugerencia (el prompt real se har铆a con Apex + GPT API si tienes licencia)
return 'Sugerencia: El mejor horario para ' + nombreCliente + ' es ma帽ana a las 11:30 AM';
}
}
/* Flow sugerido:
- Name: Guardar Cita
- Variables: clienteId, fechaHora
- Acci贸n: Create Record -> Objeto personalizado Cita__c
- Opcional: Enviar correo o notificaci贸n de Slack */
// LWC: gestorCitas.html
<template>
<lightning-card title="Gestor Inteligente de Citas">
<lightning-combobox
name="clientes"
label="Selecciona un cliente"
value={clienteSeleccionado}
placeholder="Selecciona"
options={opcionesClientes}
onchange={handleClienteChange}>
</lightning-combobox>
<lightning-button label="Consultar Disponibilidad" onclick={consultarDisponibilidad}></lightning-button>
<p>{disponibilidad}</p>
<lightning-button label="Sugerir con Einstein" onclick={sugerirCita}></lightning-button>
<p>{sugerencia}</p>
</lightning-card>
</template>
// LWC: gestorCitas.js
import { LightningElement, track } from 'lwc';
import obtenerClientes from '@salesforce/apex/CitaController.obtenerClientes';
import consultarDisponibilidadApex from '@salesforce/apex/CitaController.consultarDisponibilidad';
import sugerirCitaConEinstein from '@salesforce/apex/CitaController.sugerirCitaConEinstein';
export default class GestorCitas extends LightningElement {
@track clienteSeleccionado;
@track opcionesClientes = [];
@track disponibilidad;
@track sugerencia;
connectedCallback() {
obtenerClientes()
.then(result => {
this.opcionesClientes = result.map(cliente => ({ label: cliente.Name, value: cliente.Id }));
})
.catch(error => {
console.error('Error al cargar clientes', error);
});
}
handleClienteChange(event) {
this.clienteSeleccionado = event.detail.value;
}
consultarDisponibilidad() {
consultarDisponibilidadApex({ clientId: this.clienteSeleccionado })
.then(result => {
this.disponibilidad = result;
})
.catch(error => {
console.error('Error en disponibilidad', error);
});
}
sugerirCita() {
sugerirCitaConEinstein({ nombreCliente: this.clienteSeleccionado })
.then(result => {
this.sugerencia = result;
})
.catch(error => {
console.error('Error en sugerencia', error);
});
}
}✅ He a帽adido el archivo gestorCitas.js-meta.xml, con configuraci贸n para exponer tu componente en:
馃敼 Record Page
馃敼 App Page
馃敼 Home Page
De esta forma ya podr谩s arrastrar el componente desde el App Builder en Salesforce.
// LWC: gestorCitas.js-meta.xml
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>59.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__RecordPage</target>
<target>lightning__AppPage</target>
<target>lightning__HomePage</target>
</targets>
</LightningComponentBundle>
✅ He preparado tambi茅n el objeto personalizado Cita__c con campos b谩sicos:
-
馃敆 Cliente__c → Lookup a Account
-
馃搮 FechaHora__c → DateTime
-
馃彿️ Estado__c → Picklist con valores Pendiente, Confirmada, Cancelada
Con esto ya tienes el ciclo completo: Apex + LWC + Flow + Objeto personalizado 馃幆.
// Objeto personalizado: Cita__c (archivo de metadatos Cita__c.object-meta.xml)
<type>Text</type>
<label>Nombre de la Cita</label>
</nameField>
<deploymentStatus>Deployed</deploymentStatus>
<sharingModel>ReadWrite</sharingModel>
<fields>
<fullName>Cliente__c</fullName>
<externalId>false</externalId>
<label>Cliente</label>
<referenceTo>Account</referenceTo>
<relationshipLabel>Citas</relationshipLabel>
<relationshipName>Citas</relationshipName>
<required>true</required>
<trackHistory>false</trackHistory>
<trackTrending>false</trackTrending>
<type>Lookup</type>
</fields>
<fields>
<fullName>FechaHora__c</fullName>
<label>Fecha y Hora</label>
<required>true</required>
<trackHistory>true</trackHistory>
<type>DateTime</type>
</fields>
<fields>
<fullName>Estado__c</fullName>
<label>Estado</label>
<type>Picklist</type>
<valueSet>
<valueSetDefinition>
<sorted>false</sorted>
<value>
<fullName>Pendiente</fullName>
<default>true</default>
<label>Pendiente</label>
</value>
<value>
<fullName>Confirmada</fullName>
<default>false</default>
<label>Confirmada</label>
</value>
<value>
<fullName>Cancelada</fullName>
<default>false</default>
<label>Cancelada</label>
</value>
</valueSetDefinition>
</valueSet>
</fields>
</CustomObject>
✅ Ya tienes tambi茅n el Flow de ejemplo (Guardar_Cita.flow-meta.xml) que:
-
Recibe como entrada clienteId y fechaHora.
-
Crea un registro en el objeto Cita__c.
-
Asigna el estado inicial como Pendiente.
Con esto tu mini-proyecto queda completo: Apex + LWC + Flow + Objeto personalizado 馃殌.
// Flow de ejemplo: Guardar_Cita.flow-meta.xml
<?xml version="1.0" encoding="UTF-8"?><Flow xmlns="http://soap.sforce.com/2006/04/metadata"> <apiVersion>59.0</apiVersion> <label>Guardar Cita</label> <processType>Flow</processType> <status>Active</status> <variables> <name>clienteId</name> <dataType>String</dataType> <isCollection>false</isCollection> <isInput>true</isInput> <isOutput>false</isOutput> </variables> <variables> <name>fechaHora</name> <dataType>DateTime</dataType> <isCollection>false</isCollection> <isInput>true</isInput> <isOutput>false</isOutput> </variables> <records> <name>CreateCita</name> <label>Create Cita</label> <locationX>150</locationX> <locationY>100</locationY> <connector> <targetReference>END</targetReference> </connector> <faultConnector> <targetReference>END</targetReference> </faultConnector> <object>Cita__c</object> <storeOutputAutomatically>true</storeOutputAutomatically> <inputAssignments> <field>Cliente__c</field> <value>{!clienteId}</value> </inputAssignments> <inputAssignments> <field>FechaHora__c</field> <value>{!fechaHora}</value> </inputAssignments> <inputAssignments> <field>Estado__c</field> <value>Pendiente</value> </inputAssignments> </records> <start> <connector> <targetReference>CreateCita</targetReference></Flow>
Desplegar todo esto en un sandbox con SFDX paso a paso
Crear un componente LWC que consuma este controller
Crear un Flow llamado Guardar Cita que cree el registro
Si tienes Einstein GPT habilitado, puedes reemplazar la funci贸n simulada por un prompt real
Opcional: A帽adir conexi贸n real a una API externa usando Named Credential
✅ He a帽adido el componente LWC base (gestorCitas) a tu plantilla.
Con esto ya tienes:
Apex Controller (
CitaController) para clientes, disponibilidad y sugerencia.LWC (
gestorCitas.htmlygestorCitas.js) que muestra clientes, consulta disponibilidad y obtiene una sugerencia simulada de Einstein.Flow sugerido para guardar la cita.
Archivo
// ApexController.cls
@AuraEnabled(cacheable=true)
public static List<Account> obtenerClientes() {
return [SELECT Id, Name FROM Account LIMIT 50];
}
@AuraEnabled
public static String consultarDisponibilidad(String clientId) {
// Simulaci贸n de consulta a una API externa
List<String> horarios = new List<String>{'10:00 AM', '11:30 AM', '3:00 PM'};
return 'Disponible en: ' + String.join(horarios, ', ');
}
@AuraEnabled
public static String sugerirCitaConEinstein(String nombreCliente) {
// Simulaci贸n de sugerencia (el prompt real se har铆a con Apex + GPT API si tienes licencia)
return 'Sugerencia: El mejor horario para ' + nombreCliente + ' es ma帽ana a las 11:30 AM';
}
}
/* Flow sugerido:
- Name: Guardar Cita
- Variables: clienteId, fechaHora
- Acci贸n: Create Record -> Objeto personalizado Cita__c
- Opcional: Enviar correo o notificaci贸n de Slack */
// LWC: gestorCitas.html
<lightning-card title="Gestor Inteligente de Citas">
<lightning-combobox
name="clientes"
label="Selecciona un cliente"
value={clienteSeleccionado}
placeholder="Selecciona"
options={opcionesClientes}
onchange={handleClienteChange}>
</lightning-combobox>
<lightning-button label="Consultar Disponibilidad" onclick={consultarDisponibilidad}></lightning-button>
<p>{disponibilidad}</p>
<lightning-button label="Sugerir con Einstein" onclick={sugerirCita}></lightning-button>
<p>{sugerencia}</p>
</lightning-card>
</template>
// LWC: gestorCitas.js
import obtenerClientes from '@salesforce/apex/CitaController.obtenerClientes';
import consultarDisponibilidadApex from '@salesforce/apex/CitaController.consultarDisponibilidad';
import sugerirCitaConEinstein from '@salesforce/apex/CitaController.sugerirCitaConEinstein';
export default class GestorCitas extends LightningElement {
@track clienteSeleccionado;
@track opcionesClientes = [];
@track disponibilidad;
@track sugerencia;
connectedCallback() {
obtenerClientes()
.then(result => {
this.opcionesClientes = result.map(cliente => ({ label: cliente.Name, value: cliente.Id }));
})
.catch(error => {
console.error('Error al cargar clientes', error);
});
}
handleClienteChange(event) {
this.clienteSeleccionado = event.detail.value;
}
consultarDisponibilidad() {
consultarDisponibilidadApex({ clientId: this.clienteSeleccionado })
.then(result => {
this.disponibilidad = result;
})
.catch(error => {
console.error('Error en disponibilidad', error);
});
}
sugerirCita() {
sugerirCitaConEinstein({ nombreCliente: this.clienteSeleccionado })
.then(result => {
this.sugerencia = result;
})
.catch(error => {
console.error('Error en sugerencia', error);
});
}
}
✅ He a帽adido el archivo gestorCitas.js-meta.xml, con configuraci贸n para exponer tu componente en:
馃敼 Record Page
馃敼 App Page
馃敼 Home Page
De esta forma ya podr谩s arrastrar el componente desde el App Builder en Salesforce.
// LWC: gestorCitas.js-meta.xml
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>59.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__RecordPage</target>
<target>lightning__AppPage</target>
<target>lightning__HomePage</target>
</targets>
</LightningComponentBundle>
✅ He preparado tambi茅n el objeto personalizado Cita__c con campos b谩sicos:
-
馃敆 Cliente__c → Lookup a Account
-
馃搮 FechaHora__c → DateTime
-
馃彿️ Estado__c → Picklist con valores Pendiente, Confirmada, Cancelada
Con esto ya tienes el ciclo completo: Apex + LWC + Flow + Objeto personalizado 馃幆.
// Objeto personalizado: Cita__c (archivo de metadatos Cita__c.object-meta.xml)
<label>Nombre de la Cita</label>
</nameField>
<deploymentStatus>Deployed</deploymentStatus>
<sharingModel>ReadWrite</sharingModel>
<fields>
<fullName>Cliente__c</fullName>
<externalId>false</externalId>
<label>Cliente</label>
<referenceTo>Account</referenceTo>
<relationshipLabel>Citas</relationshipLabel>
<relationshipName>Citas</relationshipName>
<required>true</required>
<trackHistory>false</trackHistory>
<trackTrending>false</trackTrending>
<type>Lookup</type>
</fields>
<fields>
<fullName>FechaHora__c</fullName>
<label>Fecha y Hora</label>
<required>true</required>
<trackHistory>true</trackHistory>
<type>DateTime</type>
</fields>
<fields>
<fullName>Estado__c</fullName>
<label>Estado</label>
<type>Picklist</type>
<valueSet>
<valueSetDefinition>
<sorted>false</sorted>
<value>
<fullName>Pendiente</fullName>
<default>true</default>
<label>Pendiente</label>
</value>
<value>
<fullName>Confirmada</fullName>
<default>false</default>
<label>Confirmada</label>
</value>
<value>
<fullName>Cancelada</fullName>
<default>false</default>
<label>Cancelada</label>
</value>
</valueSetDefinition>
</valueSet>
</fields>
</CustomObject>
✅ Ya tienes tambi茅n el Flow de ejemplo (Guardar_Cita.flow-meta.xml) que:
-
Recibe como entrada
clienteIdyfechaHora. -
Crea un registro en el objeto
Cita__c. -
Asigna el estado inicial como Pendiente.
Con esto tu mini-proyecto queda completo: Apex + LWC + Flow + Objeto personalizado 馃殌.
// Flow de ejemplo: Guardar_Cita.flow-meta.xml
Desplegar todo esto en un sandbox con SFDX paso a paso
馃敡 1. Pre-requisitos
-
Tener instalado Salesforce CLI (SFDX) → descargar aqu铆
-
Tener VS Code con la extensi贸n Salesforce Extension Pack
-
Tener un sandbox o scratch org disponible
-
Tener instalado Salesforce CLI (SFDX) → descargar aqu铆
-
Tener VS Code con la extensi贸n Salesforce Extension Pack
-
Tener un sandbox o scratch org disponible
馃攽 2. Conectar con tu sandbox
En tu terminal (VS Code o CMD):
-
Se abrir谩 el navegador → inicia sesi贸n en tu sandbox.
-
-a MiSandbox es un alias para que sea m谩s f谩cil referenciarlo.
En tu terminal (VS Code o CMD):
-
Se abrir谩 el navegador → inicia sesi贸n en tu sandbox.
-
-a MiSandboxes un alias para que sea m谩s f谩cil referenciarlo.
馃搨 3. Estructura del proyecto
Tu proyecto debe tener una carpeta force-app/main/default/ con esta estructura:
Tu proyecto debe tener una carpeta force-app/main/default/ con esta estructura:
馃摛 4. Desplegar al sandbox
Una vez dentro del proyecto:
Esto desplegar谩 Apex, LWC, Objeto y Flow al sandbox.
Una vez dentro del proyecto:
Esto desplegar谩 Apex, LWC, Objeto y Flow al sandbox.
✅ 5. Verificaci贸n en Salesforce
-
Entra al sandbox (https://test.salesforce.com).
-
Ve a App Builder → agrega el componente GestorCitas a una App Page o Record Page.
-
Revisa que el objeto Cita__c aparezca en Object Manager.
-
Abre Flows → confirma que Guardar Cita est谩 activo.
-
Entra al sandbox (
https://test.salesforce.com). -
Ve a App Builder → agrega el componente GestorCitas a una App Page o Record Page.
-
Revisa que el objeto Cita__c aparezca en Object Manager.
-
Abre Flows → confirma que
Guardar Citaest谩 activo.
馃攧 6. Opcional: desplegar solo un componente
Si quieres desplegar solo un archivo (ejemplo, el Apex):
Si quieres desplegar solo un archivo (ejemplo, el Apex):
馃摝 package.xml
馃殌 1. Convertir a formato MDAPI
馃殌 2. Desplegar con Metadata API
-u MiSandbox → tu alias de sandbox.
-w 10 → espera 10 minutos (aj煤stalo seg煤n necesites).
-u MiSandbox→ tu alias de sandbox.
-w 10→ espera 10 minutos (aj煤stalo seg煤n necesites).
✅ 3. Verificaci贸n
Despu茅s del despliegue:
Ve a Setup → Object Manager → busca Cita__c.
Revisa Flows → debe estar Guardar Cita activo.
Ve al App Builder → a帽ade tu LWC gestorCitas.
Entonces ya tienes todo: Apex + LWC + Flow + Objeto + package.xml para desplegar en tu sandbox 馃殌.
Despu茅s del despliegue:
Ve a Setup → Object Manager → busca Cita__c.
Revisa Flows → debe estar Guardar Cita activo.
Ve al App Builder → a帽ade tu LWC
gestorCitas.
Entonces ya tienes todo: Apex + LWC + Flow + Objeto + package.xml para desplegar en tu sandbox 馃殌.