REDA One Centro de ayuda
ES
Idioma
English EN Español ES Português PT Italiano próximamente Français FR Deutsch próximamente العربية próximamente
reda.one ↗
Inicio / REDA Financials AI / API e integración / Extensibilidad / Paquetes de extensión

Paquetes de extensión

Algunas integraciones son productos en sí mismos — feeds bancarios con credenciales de proveedor, facturación electrónica frente a APIs gubernamentales. REDA Financials estructura estas integraciones como paquetes de extensión: el núcleo define un contrato abstracto global, la extensión lo implementa y un registro de configuración conecta ambos. Hoy se distribuyen dos contratos base, más tres interfaces de capacidad opcionales que un proveedor implementa solo si las necesita.

Cómo funciona el patrón

Ambos contratos siguen la misma arquitectura, y los dos encabezados de clase lo describen con las mismas palabras: "The core package resolves the provider at runtime via: Type.forName(setup.Provider_Class__c).newInstance()". Ningún contrato codifica un proveedor de forma fija. Hay cuatro piezas móviles, cada una con un dueño claro:

PiezaDueñoRol
Contrato abstracto — refin.BankFeedProvider / refin.EInvoiceProviderPaquete núcleoClases abstractas globales (ambas marcadas @since 2026-05-28) que definen las firmas de método y las formas de resultado. Global = parte de la superficie estable del paquete gestionado.
ImplementaciónPaquete de extensión (o tu org)Una clase concreta que extiende el contrato; contiene toda la lógica de API específica del proveedor. Según ambas documentaciones de clase: "Authentication and API credentials are managed entirely by the extension package."
Registro de configuración — refin__Bank_Feed_Setup__c / refin__E_Invoice_Setup__cTu administradorRegistra la clase implementadora con nombre completo en Provider_Class__c, además del entorno, la activación y la configuración de alcance.
Objeto de resultado — BankFeedResult / EInvoiceResultPaquete núcleoLa clase interna global que devuelve cada método, de modo que los resultados se registran de manera uniforme sin importar el proveedor.
Contratos vs. orquestación. Este artículo documenta los contratos de extensión — las dos clases globales y sus objetos de configuración, que son la superficie estable y publicada. La manera en que el paquete núcleo orquesta estos contratos en tiempo de ejecución (trabajos de sincronización programados, creación automática de historiales al contabilizar documentos) depende de la versión y sigue evolucionando. Diseña y programa contra los contratos; confirma con REDA el comportamiento de orquestación de tu versión instalada del núcleo antes de comprometer un diseño operativo a partir de él.

refin.BankFeedProvider — extractos bancarios automatizados

  • El contrato: tres métodos que aporta una implementación — connect (el flujo de vinculación del proveedor), sync (recuperar transacciones desde el cursor y entregar líneas de extracto), disconnect (revocar el acceso). Los resultados se devuelven en una forma estándar (éxito, transacciones importadas, cursor actualizado, saldo, error).
  • La conexión: un registro de Configuración de feed bancario por cada cuenta conectada — nombre del proveedor, entorno (Sandbox/Producción), el nombre de la clase implementadora, cursor y estado de sincronización (Active / Paused / Error / Disconnected), última sincronización. Las configuraciones viven en la página de registro de la cuenta bancaria.
  • Las credenciales permanecen en la extensión — el núcleo nunca ve los tokens del proveedor; la extensión gestiona su autenticación de principio a fin.
  • El resultado: los extractos llegan como extractos bancarios comunes (con el origen de importación marcado en consecuencia) y fluyen hacia el mismo emparejamiento y conciliación que tendría un CSV — automatización aguas arriba, flujo de trabajo conocido aguas abajo.

El contrato del feed bancario, método por método

Cada método recibe el registro de configuración como contexto. La documentación de la clase describe el modelo: "Each method receives the Bank_Feed_Setup__c record as the primary context — the provider reads the linked bank account and its own credentials to execute sync logic."

global abstract BankFeedResult sync(refin__Bank_Feed_Setup__c setup);

global abstract BankFeedResult connect(
    refin__Bank_Feed_Setup__c setup,
    Map<String, String> params
);

global abstract void disconnect(refin__Bank_Feed_Setup__c setup);
MétodoQué exige el contrato de él (según la documentación de la clase)
sync"The provider fetches new transactions from the bank API (using the sync cursor from the setup record), converts them to Bank Statement Lines via the core package's internal import path, and returns the updated cursor for persistence." La documentación agrega que es "Called by the core scheduled batch job" — ver la salvedad de orquestación anterior; el lado de la programación depende de la versión del núcleo.
connectInicia el flujo de vinculación de una nueva cuenta bancaria. "Provider-specific: may involve OAuth redirect, token exchange, or API key validation. The params map carries provider-specific connection parameters (e.g. public_token for Plaid, link_id for Belvo)."
disconnect"Revokes access tokens, removes webhooks, and cleans up provider-side resources. The core package updates the setup record's Sync_Status to Disconnected after this method completes."

BankFeedResult es una clase interna global — cada miembro es @AuraEnabled global, y el constructor establece por defecto success en false y transactionsImported en 0, de modo que una implementación debe ganarse un éxito:

MiembroTipoSignificado
successBooleanSi la operación se completó. Por defecto, false.
transactionsImportedIntegerCuántas transacciones entregó la sincronización. Por defecto, 0.
updatedCursorStringLa nueva posición incremental, devuelta "for persistence" para que la siguiente sincronización retome donde terminó esta.
currentBalanceDecimalEl saldo de la cuenta reportado por el proveedor al momento de la sincronización.
errorMessageStringDetalle honesto del fallo cuando success es false.

refin__Bank_Feed_Setup__c — referencia de campos

CampoQué contiene
Bank_Account__cLa cuenta bancaria de REDA a la que sirve este feed — una configuración por cuenta conectada.
Provider_Class__c (etiqueta "Provider Class")El corazón de la conexión. Descripción textual: "Fully qualified Apex class name that extends refin.BankFeedProvider… Extension packages register their implementation here (e.g. plaid.PlaidBankFeedProvider)."
Provider__cSolo nombre para mostrar — según su propia descripción, "The actual integration logic is determined by Provider_Class__c, not this field."
Environment__cA qué entorno del proveedor apunta la conexión (Sandbox / Producción).
Is_Active__cSi el feed participa en la sincronización.
Sync_Cursor__cLa posición incremental del proveedor — sync la lee y devuelve el valor actualizado en BankFeedResult.updatedCursor.
Sync_Status__cLista de selección: Active / Paused / Error / Disconnected. La ayuda del valor Error es explícita: "Error: last sync failed — check Audit Log for details."
Last_Sync__cCuándo se sincronizó el feed por última vez.
Provider_Account_Id__cEl identificador del lado del proveedor para la cuenta vinculada.
Cómo llegan realmente las líneas de extracto. La documentación de la clase indica que el proveedor escribe las transacciones en Bank_Statement__c / Bank_Statement_Line__c a través del servicio de importación interno del paquete núcleo — pero ese servicio no forma parte de la superficie global, así que el mecanismo exacto de entrega de extractos disponible para una extensión depende de tu versión del paquete núcleo. Trata el contrato (recuperar, entregar, devolver el cursor) como fijo y confirma la ruta de entrega con REDA al construir un proveedor.

Un esqueleto de implementación

Así es la forma de un proveedor — el equipo de Meridian esbozando uno contra la API directa de su banco estadounidense. Solo las piezas del contrato son reales; los comentarios marcan dónde va tu lógica de proveedor:

global class MeridianBankFeedProvider extends refin.BankFeedProvider {

    global override refin.BankFeedProvider.BankFeedResult connect(
            refin__Bank_Feed_Setup__c setup, Map<String, String> params) {
        refin.BankFeedProvider.BankFeedResult result =
            new refin.BankFeedProvider.BankFeedResult();
        // Intercambia los parámetros de conexión (p. ej. public_token) con el
        // proveedor. Guarda las credenciales en TU paquete — nunca en objetos del núcleo.
        result.success = true;
        return result;
    }

    global override refin.BankFeedProvider.BankFeedResult sync(
            refin__Bank_Feed_Setup__c setup) {
        refin.BankFeedProvider.BankFeedResult result =
            new refin.BankFeedProvider.BankFeedResult();
        // 1. Recupera las transacciones desde setup.refin__Sync_Cursor__c
        // 2. Entrégalas como líneas de extracto bancario
        // 3. Devuelve el nuevo cursor para que pueda persistirse
        result.transactionsImported = 42;
        result.updatedCursor = 'cursor-after-this-batch';
        result.success = true;
        return result;
    }

    global override void disconnect(refin__Bank_Feed_Setup__c setup) {
        // Revoca tokens y webhooks del lado del proveedor; el núcleo
        // establece Sync_Status en Disconnected después de que esto se complete.
    }
}

refin.EInvoiceProvider — facturación electrónica estatutaria

  • El contrato: submit (construir la carga útil de la jurisdicción a partir del documento y llamar a la autoridad), checkStatus (consultar autoridades asíncronas), cancel (aplican reglas específicas de la jurisdicción — la propia nota del contrato cita la ventana de 24 horas de Brasil y la aceptación del receptor en México).
  • La conexión: una Configuración de facturación electrónica por entidad/país — proveedor, entorno, clase implementadora, qué tipos de documento participan y una opción Auto Submit On Post; cada intento de envío se registra como un Historial de facturación electrónica en el documento (estado, UUID y número fiscal, cargas útiles, respuesta, cantidad de reintentos) — el rastro de auditoría de cumplimiento que exigen los reguladores.
  • Nota de disponibilidad: los historiales y las listas relacionadas son visibles en toda la aplicación (ya has visto Historiales de facturación electrónica en las páginas de facturas); el envío en vivo requiere la extensión de proveedor de tu jurisdicción — confirma con REDA qué está disponible para tu país.

El contrato de facturación electrónica, método por método

MétodoFirmaContrato
submitglobal abstract EInvoiceResult submit(refin__E_Invoice_Trail__c trail, SObject sourceDocument)El documento de origen es un refin__Sales_Invoice__c o refin__Purchase_Invoice__c; el proveedor construye el XML/JSON de la jurisdicción y llama a la API gubernamental; el núcleo actualiza el Trail a partir del resultado
checkStatusglobal abstract EInvoiceResult checkStatus(refin__E_Invoice_Trail__c trail)Consulta para autoridades asíncronas que responden más tarde
cancelglobal abstract EInvoiceResult cancel(refin__E_Invoice_Trail__c trail)"Jurisdiction-specific rules apply (e.g. Brazil NF-e cancellation within 24h, Mexico CFDI cancellation with receiver acceptance)."

Los tres métodos devuelven un EInvoiceResult — miembros: success, status, fiscalUUID, fiscalNumber, responseCode, responseMessage, xmlPayload, responsePayload, errorMessage.

Los objetos de facturación electrónica — referencia de campos

Campo de refin__E_Invoice_Setup__cRol
Entity__c · Country_Code__c · Environment__c · Is_Active__cQué empresa, qué jurisdicción, prueba vs. producción, activado/desactivado
Provider__cSolo nombre para mostrar
Provider_Class__cLa clase Apex con nombre completo que extiende refin.EInvoiceProvider (el ejemplo del propio campo: sovos.SovosEInvoiceProvider)
Document_Types__cSelección múltiple: Sales Invoice / Credit Memo / Purchase Invoice / Vendor Memo — el "core package checks this field when determining whether to create an E-Invoice Trail record"
Auto_Submit_On_Post__cTextual: "When checked, posting a Sales Invoice or Purchase Invoice automatically creates an E-Invoice Trail record in Draft status, triggering the asynchronous submission process. When unchecked, e-invoice submission must be initiated manually via a quick action or API call."

El registro refin__E_Invoice_Trail__c es la fila de auditoría por envío: búsquedas a la configuración y a la factura de origen, Document_Type__c, Status__c, Fiscal_UUID__c, Fiscal_Number__c, XML_Payload__c, los campos de respuesta (Response_Code__c/Message__c/Payload__c/Date__c), Submitted_Date__c, Retry_Count__c y Provider_Document_Id__c — la cadena de evidencia que esperan los reguladores, una fila por intento. Status__c tiene ocho valores: Draft, Ready to Send, Queued, Submitted, Accepted, Rejected, Cancelled, Error.

¿Por qué contratos en lugar de funciones integradas? Las APIs bancarias y las autoridades fiscales difieren por país y cambian según sus propios calendarios. Un contrato global estable permite que los paquetes especializados evolucionen a su propio ritmo — y permite que tu org cambie de proveedor modificando un registro de configuración, sin reimplementar la banca.

Interfaces de capacidad opcionales — cómo crece un contrato congelado

refin.EInvoiceProvider se publicó como clase abstracta global en una versión Managed-Released, lo que significa que nunca se le puede añadir un método. En lugar de congelar el marco con ella, REDA añade el comportamiento nuevo como interfaces globales independientes, algo que Salesforce sí permite. Un proveedor extiende EInvoiceProvider y implementa las interfaces de capacidad que admite; el núcleo detecta el soporte con instanceof y simplemente omite la capacidad para los proveedores que no la implementan.

InterfazMétodosImpleméntala cuando
refin.EInvoiceQueueProviderdrain(setup, maxRecords) que devuelve List<EInvoiceEvent>; acknowledge(setup, events)Tu autoridad fiscal responde mediante una cola de notificaciones y no con una respuesta síncrona. Un solo drenaje lleva ambas direcciones — actualizaciones de estado salientes y documentos de proveedor entrantes — diferenciadas por EInvoiceEvent.processType. Deliberadamente no hay un método aparte para "traer entrantes".
refin.EInvoiceDocumentProviderfetchDocuments(trail) que devuelve List<EInvoiceDocument>Recuperas los artefactos legales (XML firmado, respuesta de la autoridad, una representación imprimible como el DANFE de Brasil) bajo demanda en lugar de entregarlos en línea con el evento. Omítela si tus eventos ya traen documents.
refin.EInvoiceProvisionerprovisionOrganization(setup, args); provisionCompany(setup, args), ambos devuelven EInvoiceProvisionResultAdmites el aprovisionamiento autoservicio de las estructuras de cuenta del lado de la autoridad desde la propia aplicación. Es una capacidad de fase posterior: hoy esas estructuras las crea manualmente el proveedor de cumplimiento. Se declara ahora precisamente porque una API global ya publicada no se puede extender después.
Confirma solo después de haber persistido. El núcleo llama a acknowledge únicamente cuando cada evento ya está almacenado de forma duradera; confirmar antes perdería la notificación para siempre. Un proveedor no debe activar ningún modo de confirmación automática que se adelante a esa llamada, y drain debe devolver solo notificaciones sin confirmar, para que los drenajes sucesivos avancen.

Los tres tipos de datos que intercambian

  • refin.EInvoiceEvent: un hito en la vida de un documento ante la autoridad. El núcleo lo correlaciona con un rastro mediante erpDocumentId, un valor que tu proveedor estampa en el sobre saliente y que la autoridad devuelve. status se normaliza a Accepted, Rejected, Cancelled o InProgress: el núcleo basa los reintentos y los estados terminales en ese campo, nunca en el responseCode crudo. También lleva notificationId, processType (Outbound / Inbound), responseMessage, fiscalUUID, fiscalNumber, una lista opcional documents, payload y eventDate.
  • refin.EInvoiceDocument: un artefacto, con title, fileExtension ('xml' o 'pdf'), base64Body y documentKind ('Legal', 'LegalResponse' o 'Representation'). El núcleo lo decodifica y lo adjunta al rastro y a la factura de origen como archivos de Salesforce, para que los usuarios vean los artefactos conformes en el registro con el que ya trabajan.
  • refin.EInvoiceProvisionResult: success (que por defecto es false), externalId (el identificador del lado del proveedor) y message.

documentKind, processType y status son todos String y no enumeraciones, deliberadamente, para que el conjunto permitido pueda crecer sin romper una firma global congelada. No hagas un switch exhaustivo sobre ellos: gestiona los valores que conoces y deja pasar el resto.

Errores comunes que evitar

ErrorPor qué perjudicaHaz esto en su lugar
Errores de tipeo en Provider_Class__cLa resolución en tiempo de ejecución es por nombre — una cadena incorrecta significa que el proveedor simplemente nunca se ejecutaCopia el nombre completo (namespace.ClassName) desde la documentación de la extensión; prueba la conexión de inmediato
Confiar en Provider__c para cambiar de proveedorEs una etiqueta de visualización; "The actual integration logic is determined by Provider_Class__c, not this field."Cambia Provider_Class__c; actualiza la etiqueta para los humanos
Almacenar credenciales de autoridades/bancos en los registros de configuraciónEl contrato es explícito: "Authentication and API credentials are managed entirely by the extension package"Las credenciales viven en las credenciales con nombre propias de la extensión, gobernadas por la seguridad de tu org
Construir el código de tu org contra los internos de un paquete de proveedorLos paquetes de proveedor evolucionan según su propio calendario — solo los contratos globales refin. son la costura estableIntégrate a través de los registros de configuración y los historiales; trata al proveedor como una caja negra
Asumir detalles de orquestación sin probar tu versiónEl comportamiento de programación y despacho automático depende de la versiónVerifica la programación de sincronización y el comportamiento de envío automático en un sandbox de tus versiones instaladas antes de prometerlos al negocio

Para equipos que construyen una extensión

  • Implementa la clase abstracta en el namespace de tu paquete; registra el nombre de clase completo en el registro de configuración.
  • Gestiona tus propias credenciales (credenciales con nombre en tu paquete), tu mapeo de API, tu semántica de errores — devuelve resultados honestos; el núcleo los expone en Sync Status y en los historiales.
  • Construye solo contra el contrato — la superficie global documentada es la estable (las reglas).

Qué sigue

  1. Importación de extractos bancarios — el flujo donde aterrizan los feeds.
  2. Integraciones de AppExchange — el panorama más amplio del ecosistema.
  3. Desarrollo en Apex sobre REDA — las reglas de la superficie global.

Preguntas frecuentes

El contrato está diseñado para el ecosistema de agregadores (Plaid, Belvo y similares son los arquetipos que menciona). Consulta con REDA qué extensiones de proveedor están vigentes para tu región — la disponibilidad evoluciona más rápido que la documentación.

El contrato resuelve la clase implementadora por nombre, por lo que una implementación local al org es técnicamente direccionable — sensato para una API bancaria a medida. Empaquétala correctamente si va a sobrevivir a un solo org.

Depende del país (Brasil, México, Italia y Arabia Saudita lideran; muchos otros siguen). Tu asesor fiscal decide el "¿debemos?"; la configuración y la extensión del proveedor resuelven el "¿cómo?".

BankFeedResult informa success, transactionsImported, updatedCursor (dónde retoma la siguiente sincronización), currentBalance y errorMessage — los valores predeterminados son honestos (success=false, cero importado), de modo que un proveedor descuidado no pueda reportar éxito por accidente. EInvoiceResult transporta la respuesta de la autoridad: identificadores fiscales, cargas útiles de respuesta y el texto del error cuando rechazó la solicitud.

Es el estado de salud de la conexión de un vistazo — Active / Paused / Error / Disconnected. La ayuda del propio campo para el estado problemático: "Error: last sync failed — check Audit Log for details." Disconnected lo establece el núcleo después de que finaliza el disconnect de tu proveedor.

¿Te resultó útil?