Cómo Desarrollar en Smart Processing (Documentación para Desarrolladores)
Estado: 01.08.2026 • Tiempo de lectura: ~8 minutos
Smart Processing proporciona puntos de extensión donde puedes implementar lógica personalizada para iniciar tus propios procesos o adaptar el manejo a los requisitos del cliente. Este documento explica el concepto clave de desarrollo: trabajar a través de la sesión activa y activar codeunits personalizados en el proceso correspondiente utilizando los datos de la sesión.
1. Concepto Central: Trabajar a Través de la Sesión de Procesamiento Activa
Smart Processing ejecuta una “sesión de borrador activa” mientras se procesa un documento. Durante ese tiempo, se mantiene un estado relevante de manera central (contexto del documento, contexto de la plantilla, líneas coincidentes, desviaciones y datos intermedios utilizados por la interfaz de usuario y la tubería de procesamiento).
Como desarrollador, el enfoque recomendado es:
- Leer el contexto de procesamiento actual de la sesión.
- Realizar tu lógica utilizando el contexto y las referencias proporcionadas.
- Escribir resultados/estado de nuevo en la sesión cuando el flujo de trabajo lo necesite.
- Confiar en la plataforma para mantener la interfaz de usuario y el procesamiento alineados a través de la arquitectura de la sesión.
Esto hace que las personalizaciones sean estables y evita un estado inconsistente entre lo que los usuarios ven y lo que tu lógica cambió.
2. El Objeto Central: “SIM_DI Process Session SI”
El codeunit “SIM_DI Process Session SI” es el punto de entrada central para acceder y manipular la sesión activa de Smart Processing. Actúa como el centro para obtener datos de tiempo de ejecución relevantes (documento entrante, plantilla de proceso, búferes de línea, metadatos de desviación) y para comunicar resultados de vuelta a la tubería (por ejemplo, qué encabezado fue procesado).
Resumen de funciones públicas (de los ejemplos proporcionados)
La siguiente tabla enumera las funciones públicas que se utilizan realmente en tu código de ejemplo. Si una función existe en múltiples variantes (sobrecargas), los parámetros que pueden no estar presentes en cada variante se marcan como opcionales.
| Función | Qué hace | Parámetros (opcionales marcados) | Retorna |
|---|---|---|---|
InitSession |
Inicializa la sesión con un documento entrante y resuelve la plantilla de proceso relacionada. | InboundDocument |
ninguno |
InitSession |
Inicializa la sesión con un documento entrante y una plantilla de proceso proporcionada explícitamente (y borra primero los datos de la sesión anterior). | InboundDocument, ProcessTemplate |
ninguno |
GetInboundDocument |
Recupera el documento entrante almacenado en la sesión actual. | var InboundDocument |
ninguno |
GetProcessTemplate |
Recupera la plantilla de proceso almacenada en la sesión actual. | var ProcessTemplate |
ninguno |
ClearProcessSession |
Borra todo el contexto de la sesión, incluyendo el documento entrante, la plantilla de proceso, las claves de mapeo y los datos de proceso. | - | ninguno |
ClearProcessData |
Borra solo los datos de procesamiento (encabezados/filas/comentarios temporales, registros de búsqueda mapeados, id de encabezado procesado) y borra datos coincidentes. | - | ninguno |
SetProcessedHeaderRecordId |
Almacena la referencia del registro del encabezado del documento objetivo creado/coincidente en la sesión para el procesamiento posterior (por ejemplo, finalización/archivado). | RecordId |
ninguno |
GetProcessedHeaderRecordId |
Devuelve la referencia del registro del encabezado procesado almacenado y lo borra de la sesión después. | - | RecordId |
SetDocumentHeaderVariableRef |
Almacena una copia de la variable de encabezado temporal proporcionada en la sesión (utilizada como un estado de encabezado de sesión de estilo referencia). | var TempDocumentHeader (temporal) |
ninguno |
GetDocumentHeaderVariable |
Copia los datos actuales del encabezado temporal de la sesión en la variable de registro temporal proporcionada. | var TempDocumentHeader (temporal) |
ninguno |
SetDocumentLineVariableRef |
Almacena una copia de la variable de línea temporal proporcionada en la sesión (utilizada como un estado de línea de sesión de estilo referencia). | var TempDocumentLine (temporal) |
ninguno |
GetDocumentLineVariable |
Copia los datos actuales de la línea temporal de la sesión en la variable de registro temporal proporcionada. | var TempDocumentLine (temporal) |
ninguno |
SetRemarkVariableRef |
Almacena una copia de la variable de comentario temporal proporcionada en la sesión (utilizada como un estado de comentario de sesión de estilo referencia). | var DocumentRemark (temporal) |
ninguno |
RemoveDocumentRemark |
Elimina un comentario de la sesión basado en el número de línea, número de campo y área de validación. | LineNo, FieldNo, FieldValidationArea |
ninguno |
GetRemarks |
Copia todos los comentarios de la sesión en la variable de registro de comentario temporal proporcionada. | var DocumentRemark (temporal) |
ninguno |
RemoveMappedLookupRecord |
Elimina la referencia del registro de búsqueda mapeado para un campo de plantilla dado. | TemplateFieldRecordId |
ninguno |
GetMappedLookupRecord |
Recupera la referencia del registro de búsqueda mapeado para un campo de plantilla dado (si está disponible). | TemplateFieldRecordId, var MappedRecordId |
Boolean |
GetDevitatingLinesJsonObject |
Devuelve el objeto JSON que describe las líneas desviadas y sus campos no coincidentes (incluyendo el nombre de configuración de coincidencia y detalles de discrepancia). | - | JsonObject |
GetExecuteCodeunitRefRecordIds |
Recupera referencias de registro asignadas para ejecución por un codeunit específico (típicamente líneas coincidentes a procesar). | ExecuteCodeunitNo, var RecordIds |
Boolean |
GetMatchedDocumentHeader |
Recupera la referencia del registro del encabezado del documento coincidente para un nombre de configuración de coincidencia dado (si está disponible). | MatchingSetupName, var MatchedDocumentHeaderRecordId |
Boolean |
Nota: Estas son todas las funciones públicas que se pueden confirmar a partir de tus ejemplos. Si proporcionas el código fuente completo del codeunit, ampliaré esta tabla para que incluya todas las funciones públicas.
3. Personalizaciones en el Proceso de Coincidencia
Un escenario común de extensión es activar codeunits personalizados durante la coincidencia, especialmente cuando el usuario completa el borrador y se ha creado el registro del encabezado objetivo.
Un detalle clave de este mecanismo es que el codeunit personalizado se ejecuta con el registro del encabezado del tipo de documento coincidente (por ejemplo, un encabezado de compra). Este registro se convierte en tu ancla estable: puedes derivar contexto de él, crear o importar líneas, actualizar registros relacionados y luego devolver el resultado a la sesión para que la plataforma pueda continuar su flujo de trabajo.
4. Ejemplo de Codeunits de Proceso Personalizado (Código Sin Cambios)
Ejemplo 1: Importar líneas de recibo coincidentes después de la creación del encabezado
codeunit 5673320 "SIM_DI Purch.-Get Receipts"
{
Description = 'Este codeunit se utiliza como un codeunit de importación de coincidencias para recibir líneas de recibo de compra y crear líneas de factura de compra basadas en las líneas de documento coincidentes.';
TableNo = "Purchase Header"; // <-- Este es el encabezado creado después de completar el procesamiento
Access = Internal;
var
GlobalCodeunitSIMDIProcessSessionSI: Codeunit "SIM_DI Process Session SI";
GlobalCodeunitGetReceipts: Codeunit "Purch.-Get Receipt";
GlobalNoPurchaseReceiptLinesFoundLbl: Label 'No hay líneas de recibo de compra que puedan ser procesadas. Por favor, verifica las líneas de recibo de compra y comprueba si ya han sido facturadas.';
trigger OnRun()
var
LocalRecordPurchRcptLine: Record "Purch. Rcpt. Line";
LocalMatchedLineRecordId: RecordId;
LocalToExecuteRecordIds: List of [RecordId];
begin
// Recibir las líneas coincidentes que necesitan ser ejecutadas
GlobalCodeunitSIMDIProcessSessionSI.GetExecuteCodeunitRefRecordIds(Codeunit::"SIM_DI Purch.-Get Receipts", LocalToExecuteRecordIds);
// Filtrar las líneas de recibo de compra basadas en las líneas coincidentes entrantes
foreach LocalMatchedLineRecordId in LocalToExecuteRecordIds do
if LocalRecordPurchRcptLine.Get(LocalMatchedLineRecordId) then
LocalRecordPurchRcptLine.Mark(true);
// Obtener las líneas de recibo de compra que no han sido facturadas
LocalRecordPurchRcptLine.MarkedOnly(true);
LocalRecordPurchRcptLine.SetFilter("Qty. Rcd. Not Invoiced", '<>0');
// Si no se encuentran líneas de recibo de compra, lanzar un error
if LocalRecordPurchRcptLine.IsEmpty() then
Error(GlobalNoPurchaseReceiptLinesFoundLbl);
// Ejecutar el proceso para obtener líneas de recibo
GlobalCodeunitGetReceipts.SetPurchHeader(Rec);
GlobalCodeunitGetReceipts.CreateInvLines(LocalRecordPurchRcptLine);
Commit();
end;
}
Este ejemplo muestra un proceso típico impulsado por coincidencias: la sesión proporciona la lista de “registros a ejecutar”, y tu codeunit realiza una importación basada exactamente en esas referencias coincidentes.
Ejemplo 2: Actualizar campos desviados cuando se acepta la desviación
codeunit 5673350 "SIM_DI Update Deviating Fields"
{
Description = 'Este codeunit se puede utilizar para actualizar las líneas de documento vinculadas con los valores entrantes para los campos que han sido desviados durante el proceso de coincidencia y donde se acepta la desviación.';
Access = Public;
var
GlobalCodeunitSIMDIProcessSessionSI: Codeunit "SIM_DI Process Session SI";
GlobalCodeunitSIMCOREEvaluate: Codeunit "SIM_CORE Evaluate";
GlobalCodeunitSIMCOREJSON: Codeunit "SIM_CORE JSON";
trigger OnRun()
var
TempLocalRecordSIMDITempDocumentLine: Record "SIM_DI Temp. Document Line" temporary;
LocalRecordSIMDIProcessTemplate: Record "SIM_DI Process Template";
LocalRecordSIMDIInboundDocument: Record "SIM_DI Inbound Document";
LocalCodeunitSIMDILogManagement: Codeunit "SIM_DI Log Management";
LocalDocumentHeaderRecordId: RecordId;
LocalRecordId: RecordId;
LocalRecordRef: RecordRef;
LocalFieldRef: FieldRef;
LocalRecordIdText: Text;
LocalDevitatingLinesJsonObject: JsonObject;
LocalLineMatchingValidationFieldsJsonObject: JsonObject;
LocalJsonToken: JsonToken;
LocalFieldNoInteger: Integer;
LocalFieldNoText: Text;
LocalCellIndexInteger: Integer;
LocalMatchingSetupNameText: Text;
LocalOldValueText: Text;
LocalNewValueText: Text;
LocalValueVariant: Variant;
LocalDevitatingFieldUpdateLbl: Label 'La línea %1 ha sido actualizada.\El campo "%2" ha cambiado de valor "%3" a valor "%4".', Comment = '%1 = Número de Línea, %2 = Nombre del Campo, %3 = Valor Antiguo, %4 = Nuevo Valor';
begin
/// Recibir los datos de la sesión de proceso
LocalDevitatingLinesJsonObject := GlobalCodeunitSIMDIProcessSessionSI.GetDevitatingLinesJsonObject();
GlobalCodeunitSIMDIProcessSessionSI.GetDocumentLineVariable(TempLocalRecordSIMDITempDocumentLine);
GlobalCodeunitSIMDIProcessSessionSI.GetInboundDocument(LocalRecordSIMDIInboundDocument);
GlobalCodeunitSIMDIProcessSessionSI.GetProcessTemplate(LocalRecordSIMDIProcessTemplate);
// Iterar sobre los
foreach LocalRecordIdText in LocalDevitatingLinesJsonObject.keys() do begin
if not Evaluate(LocalRecordId, LocalRecordIdText) then continue;
if not LocalRecordRef.Get(LocalRecordId) then continue;
// Obtener el registro de línea actual
LocalDevitatingLinesJsonObject.Get(LocalRecordIdText, LocalJsonToken);
// Obtener el nombre de configuración de coincidencia
LocalMatchingSetupNameText := GlobalCodeunitSIMCOREJSON.GetJsonPathValueText(LocalJsonToken.AsObject(), 'MatchingSetupName');
// Obtener los campos no coincidentes como un objeto json
if not LocalJsonToken.AsObject().Get('MissMatchedFields', LocalJsonToken) then continue;
LocalLineMatchingValidationFieldsJsonObject := LocalJsonToken.AsObject();
// Iterar sobre los campos no coincidentes y actualizar la línea de documento vinculada con el valor entrante si se acepta la desviación
foreach LocalFieldNoText in LocalLineMatchingValidationFieldsJsonObject.keys() do begin
if not Evaluate(LocalFieldNoInteger, LocalFieldNoText) then continue;
LocalLineMatchingValidationFieldsJsonObject.Get(LocalFieldNoText, LocalJsonToken);
if not GlobalCodeunitSIMCOREJSON.GetJsonPathValueBoolean(LocalJsonToken.AsObject(), 'AcceptDeviation') then
continue;
if not Evaluate(LocalCellIndexInteger, GlobalCodeunitSIMCOREJSON.GetJsonPathValueText(LocalJsonToken.AsObject(), 'CellIndex')) then
continue;
LocalFieldRef := LocalRecordRef.Field(LocalFieldNoInteger);
LocalNewValueText := GlobalCodeunitSIMCOREJSON.GetJsonPathValueText(LocalJsonToken.AsObject(), 'IncomingValue');
LocalOldValueText := LocalFieldRef.Value;
// Actualizar el campo con el valor entrante
GlobalCodeunitSIMCOREEvaluate.EvaluateVariable(
LocalNewValueText,
Format(LocalFieldRef.Type),
LocalValueVariant,
false
);
LocalFieldRef.Validate(LocalValueVariant);
LocalRecordRef.Modify();
// Agregar entrada de registro
LocalCodeunitSIMDILogManagement.AddInformationInTheLog(
StrSubstNo(LocalDevitatingFieldUpdateLbl, Format(LocalRecordIdText), LocalFieldRef.Caption, LocalOldValueText, LocalNewValueText),
'SIM_DI Update Deviating Fields',
LocalRecordSIMDIInboundDocument."Entry No."
);
end;
// Recordar el id del registro del encabezado del documento para archivar el documento más tarde
GlobalCodeunitSIMDIProcessSessionSI.GetMatchedDocumentHeader(LocalMatchingSetupNameText, LocalDocumentHeaderRecordId);
end;
// Establecer el id del registro del encabezado del documento coincidente en la sesión
GlobalCodeunitSIMDIProcessSessionSI.SetProcessedHeaderRecordId(LocalDocumentHeaderRecordId);
Commit();
end;
}
Este ejemplo ilustra el “manejo de desviaciones impulsado por la sesión”: la sesión proporciona un conjunto de datos de desviación estructurado; tu código aplica las desviaciones aceptadas, registra lo que cambió y reporta el encabezado procesado de vuelta en la sesión.
5. Puntos de Personalización Adicionales
Hay más lugares donde se pueden integrar codeunits personalizados, pero el principio guía sigue siendo constante: utiliza la sesión para recuperar el contexto de procesamiento activo y para escribir de nuevo los resultados relevantes para el flujo de trabajo. Esto mantiene tus extensiones consistentes con el flujo de Smart Processing y previene la desviación de la interfaz de usuario/proceso.