Crear el objeto codeunit de Administración de extensiones de recompensas de clientes

Completado

La codeunit Administración de extensiones de recompensas de clientes encapsula la mayor parte de la lógica y la funcionalidad necesarias para la extensión de recompensas del cliente. Esta codeunit contiene ejemplos de cómo utilizar eventos para reaccionar ante acciones o comportamientos específicos que se dan dentro de su extensión.

Esta extensión incluye el requisito de realizar una llamada a un servicio externo o API para validar los códigos de activación que introduce el usuario. Por lo general, esta verificación se completa definiendo los procedimientos que toman el código de activación y luego realizan llamadas a la API. En lugar de usar ese enfoque, puede usar los eventos en AL.

Para crear una nueva codeunit en su proyecto, cree un archivo nuevo con el nombre CustomerRewardsExtMgt.Codeunit.al.

Después, agregue el código siguiente al codeunit:

codeunit 50101 "Customer Rewards Ext. Mgt"
{
    EventSubscriberInstance = StaticAutomatic;

    // Determines if the extension is activated 
    procedure IsCustomerRewardsActivated(): Boolean;
    var
        ActivationCodeInformation: Record "Activation Code Information";
    begin
        if not ActivationCodeInformation.FindFirst() then
            exit(false);

        if (ActivationCodeInformation."Date Activated" <= Today) and (Today <= ActivationCodeInformation."Expiration Date") then
            exit(true);
        exit(false);
    end;

    // Opens the Customer Rewards Assisted Setup Guide 
    procedure OpenCustomerRewardsWizard();
    var
        CustomerRewardsWizard: Page "Customer Rewards Wizard";
    begin
        CustomerRewardsWizard.RunModal();
    end;

    // Opens the Reward Level page 
    procedure OpenRewardsLevelPage();
    var
        RewardsLevelList: Page "Rewards Level List";
    begin
        RewardsLevelList.Run();
    end;

    // Determines the corresponding reward level and returns it 
    procedure GetRewardLevel(RewardPoints: Integer) RewardLevelTxt: Text;
    var
        RewardLevel: Record "Reward Level";
        MinRewardLevelPoints: Integer;
    begin
        RewardLevelTxt := NoRewardlevelTxt;

        if RewardLevel.IsEmpty() then
            exit;
        RewardLevel.SetRange("Minimum Reward Points", 0, RewardPoints);
        RewardLevel.SetCurrentKey("Minimum Reward Points"); // sorted in ascending order 

        if not RewardLevel.FindFirst() then
            exit;
        MinRewardLevelPoints := RewardLevel."Minimum Reward Points";

        if RewardPoints >= MinRewardLevelPoints then begin
            RewardLevel.Reset();
            RewardLevel.SetRange("Minimum Reward Points", MinRewardLevelPoints, RewardPoints);
            RewardLevel.SetCurrentKey("Minimum Reward Points"); // sorted in ascending order 
            RewardLevel.FindLast();
            RewardLevelTxt := RewardLevel.Level;
        end;
    end;

    // Activates Customer Rewards if activation code is validated successfully  
    procedure ActivateCustomerRewards(ActivationCode: Text): Boolean;
    var
        ActivationCodeInformation: Record "Activation Code Information";
    begin
        // raise event 
        OnGetActivationCodeStatusFromServer(ActivationCode);
        exit(ActivationCodeInformation.Get(ActivationCode));
    end;

    // publishes event 
    [IntegrationEvent(false, false)]
    procedure OnGetActivationCodeStatusFromServer(ActivationCode: Text);
    begin
    end;

    // Subscribes to OnGetActivationCodeStatusFromServer event and handles it when the event is raised 
    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Customer Rewards Ext Mgt", 'OnGetActivationCodeStatusFromServer', '', false, false)]
    local procedure OnGetActivationCodeStatusFromServerSubscriber(ActivationCode: Text);
    var
        ActivationCodeInfo: Record "Activation Code Information";
        ResponseText: Text;
        Result: JsonToken;
        JsonRepsonse: JsonToken;
    begin
        if not CanHandle() then
            exit; // use the mock 

        // Get response from external service and update activation code information if successful 
        if (GetHttpResponse(ActivationCode, ResponseText)) then begin
            JsonRepsonse.ReadFrom(ResponseText);

            if (JsonRepsonse.SelectToken('ActivationResponse', Result)) then 

                if (Result.AsValue().AsText() = 'Success') then begin

                    if (ActivationCodeInfo.FindFirst()) then
                        ActivationCodeInfo.Delete();

                    ActivationCodeInfo.Init();
                    ActivationCodeInfo.ActivationCode := ActivationCode;
                    ActivationCodeInfo."Date Activated" := Today;
                    ActivationCodeInfo."Expiration Date" := CALCDATE('<1Y>', Today);
                    ActivationCodeInfo.Insert();
            end;
        end;
    end;

    // Helper method to make calls to a service to validate activation code 
    local procedure GetHttpResponse(ActivationCode: Text; var ResponseText: Text): Boolean;
    begin
        // You will typically make external calls / http requests to your service to validate the activation code 
        // here but for the sample extension we simply return a successful dummy response 
        if ActivationCode = '' then
            exit(false);

        ResponseText := DummySuccessResponseTxt;
        exit(true);
    end;

    // Subscribes to the OnAfterReleaseSalesDoc event and increases reward points for the sell to customer in posted sales order 
    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Release Sales Document", 'OnAfterReleaseSalesDoc', '', false, false)]
    local procedure OnAfterReleaseSalesDocSubscriber(VAR SalesHeader: Record "Sales Header"; PreviewMode: Boolean; LinesWereModified: Boolean);
    var
        Customer: Record Customer;
    begin
        if SalesHeader.Status <> SalesHeader.Status::Released then
            exit;

        Customer.Get(SalesHeader."Sell-to Customer No.");
        Customer.RewardPoints += 1; // Add a point for each new sales order 
        Customer.Modify();
    end;

    // Checks if the current codeunit is allowed to handle Customer Rewards Activation requests rather than a mock. 
    local procedure CanHandle(): Boolean;
    var
        CustomerRewardsMgtSetup: Record "Customer Rewards Mgt Setup";
    begin
        if CustomerRewardsMgtSetup.Get() then
            exit(CustomerRewardsMgtSetup."Cust. Rew. Ext. Mgt. Cod. ID" = CODEUNIT::"Customer Rewards Ext Mgt");
        exit(false);
    end;

    var
        DummySuccessResponseTxt: Label '{"ActivationResponse": "Success"}', Locked = true;
        NoRewardlevelTxt: TextConst ENU = 'NONE';
} 

En las secciones siguientes se examina el código de codeunit, paso a paso.

La propiedad EventSubscriberInstance especifica cómo los métodos de suscriptor de eventos de una codeunit están vinculados a la instancia de codeunit y los eventos a los que se suscriben. Para este ejemplo, se ha establecido la propiedad StaticAutomatic, lo que significa que los suscriptores están estáticamente vinculados a eventos y que el sistema controla las instancias de la codeunit. Este es el valor predeterminado.

codeunit 50101 "Customer Rewards Ext Mgt"
{
    EventSubscriberInstance = StaticAutomatic; 

Se ha definido el método anunciante de eventos OnGetActivationCodeStatusFromServer, que acepta el código de activación que el usuario introduce como parámetro. Además, se ha definido el método de suscriptor OnGetActivationCodeStatusFromServerSubscriber para escuchar y manejar el evento.

    // publishes event 
    [IntegrationEvent(false, false)]
    procedure OnGetActivationCodeStatusFromServer(ActivationCode: Text);
    begin
    end;
al-languageCopy
    // Subscribes to OnGetActivationCodeStatusFromServer event and handles it when the event is raised 
    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Customer Rewards Ext Mgt", 'OnGetActivationCodeStatusFromServer', '', false, false)]
    local procedure OnGetActivationCodeStatusFromServerSubscriber(ActivationCode: Text);
    var
        ActivationCodeInfo: Record "Activation Code Information";
        ResponseText: Text;
        Result: JsonToken;
        JsonRepsonse: JsonToken;
    begin
        if not CanHandle() then
            exit; // use the mock 

        // Get response from external service and update activation code information if successful 
        if (GetHttpResponse(ActivationCode, ResponseText)) then begin
            JsonRepsonse.ReadFrom(ResponseText);

            if (JsonRepsonse.SelectToken('ActivationResponse', Result)) then 

                if (Result.AsValue().AsText() = 'Success') then begin

                    if (ActivationCodeInfo.FindFirst()) then
                        ActivationCodeInfo.Delete();

                    ActivationCodeInfo.Init();
                    ActivationCodeInfo.ActivationCode := ActivationCode;
                    ActivationCodeInfo."Date Activated" := Today;
                    ActivationCodeInfo."Expiration Date" := CALCDATE('<1Y>', Today);
                    ActivationCodeInfo.Insert();
            end;
        end;
    end; 

Cuando se ejecuta el procedimiento ActivateCustomerRewards, se activa el evento OnGetActivationCodeStatusFromServer.

    // Activates Customer Rewards if activation code is validated successfully  
    procedure ActivateCustomerRewards(ActivationCode: Text): Boolean;
    var
        ActivationCodeInformation: Record "Activation Code Information";
    begin
        // raise event 
        OnGetActivationCodeStatusFromServer(ActivationCode);
        exit(ActivationCodeInformation.Get(ActivationCode));
    end; 

Dado que la propiedad EventSubscriberInstance de la codeunit se establece en StaticAutomatic de manera predeterminada, se llama al procedimiento OnGetActivationCodeStatusFromServerSubscriber.

En este procedimiento, manejará el evento activado verificando primero si se ha definido la codeunit actual para controlarlo.

        if not CanHandle() then
            exit; // use the mock 
al-languageCopy
    // Checks if the current codeunit is allowed to handle Customer Rewards Activation requests rather than a mock. 
    local procedure CanHandle(): Boolean;
    var
        CustomerRewardsMgtSetup: Record "Customer Rewards Mgt Setup";
    begin
        if CustomerRewardsMgtSetup.Get() then
            exit(CustomerRewardsMgtSetup."Cust. Rew. Ext. Mgt. Cod. ID" = CODEUNIT::"Customer Rewards Ext Mgt");
        exit(false);
    end; 

Si la codeunit puede manejar el evento, se llama al procedimiento auxiliar GetHttpResponse para validar el código de activación. Recompensas de clientes se activa o no se activa dependiendo de la respuesta.

        // Get response from external service and update activation code information if successful 
        if (GetHttpResponse(ActivationCode, ResponseText)) then begin
            JsonRepsonse.ReadFrom(ResponseText); 
    // Helper method to make calls to a service to validate activation code 
    local procedure GetHttpResponse(ActivationCode: Text; var ResponseText: Text): Boolean;
    begin
        // You will typically make external calls / http requests to your service to validate the activation code 
        // here but for the sample extension we simply return a successful dummy response 
        if ActivationCode = '' then
            exit(false);

        ResponseText := DummySuccessResponseTxt;
        exit(true);
    end; 

Mediante el uso de eventos cuando la extensión realiza llamadas externas a un servicio, es posible imitar el comportamiento de lo que sucede cuando se activan eventos.

El procedimiento IsCustomerRewardsActivated busca un código de activación en la tabla de información de códigos de activación y, además, verifica si el código está activo o ha caducado.

    // Determines if the extension is activated 
    procedure IsCustomerRewardsActivated(): Boolean;
    var
        ActivationCodeInformation: Record "Activation Code Information";
    begin
        if not ActivationCodeInformation.FindFirst() then
            exit(false);

        if (ActivationCodeInformation."Date Activated" <= Today) and (Today <= ActivationCodeInformation."Expiration Date") then
            exit(true);
        exit(false);
    end; 

Este procedimiento aparece en la página Lista de niveles de recompensas y en la extensión de página Ext. de lista de clientes.

El procedimiento OpenCustomerRewardsWizard ejecuta la página Asistente de recompensas para clientes:

    // Opens the Customer Rewards Assisted Setup Guide 
    procedure OpenCustomerRewardsWizard();
    var
        CustomerRewardsWizard: Page "Customer Rewards Wizard";
    begin
        CustomerRewardsWizard.RunModal();
    end; 

Esta página se crea en un módulo posterior, por lo que por ahora no se compilará. Puede comentar el procedimiento y eliminar los comentarios después de probar la extensión.

El procedimiento OpenRewardsLevelPage abre la página Lista de niveles de recompensa.

    // Opens the Reward Level page 
    procedure OpenRewardsLevelPage();
    var
        RewardsLevelList: Page "Rewards Level List";
    begin
        RewardsLevelList.Run();
    end; 

A este procedimiento se hace referencia desde los objetos siguientes:

  • Extensión de página Extensión de lista de clientes

  • Página Asistente de recompensas para clientes

El procedimiento GetRewardLevel determina el nivel de recompensa correspondiente y luego lo devuelve.

    // Determines the corresponding reward level and returns it 
    procedure GetRewardLevel(RewardPoints: Integer) RewardLevelTxt: Text;
    var
        RewardLevel: Record "Reward Level";
        MinRewardLevelPoints: Integer;
    begin
        RewardLevelTxt := NoRewardlevelTxt;

        if RewardLevel.IsEmpty() then
            exit;
        RewardLevel.SetRange("Minimum Reward Points", 0, RewardPoints);
        RewardLevel.SetCurrentKey("Minimum Reward Points"); // sorted in ascending order 

        if not RewardLevel.FindFirst() then
            exit;
        MinRewardLevelPoints := RewardLevel."Minimum Reward Points";

        if RewardPoints >= MinRewardLevelPoints then begin
            RewardLevel.Reset();
            RewardLevel.SetRange("Minimum Reward Points", MinRewardLevelPoints, RewardPoints);
            RewardLevel.SetCurrentKey("Minimum Reward Points"); // sorted in ascending order 
            RewardLevel.FindLast();
            RewardLevelTxt := RewardLevel.Level;
        end;
    end; 

A este procedimiento se hace referencia desde la extensión de página Extensión de ficha cliente.

Por último, se ejecuta el procedimiento OnAfterReleaseSalesDocSubscriber.

    // Subscribes to the OnAfterReleaseSalesDoc event and increases reward points for the sell to customer in posted sales order 
    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Release Sales Document", 'OnAfterReleaseSalesDoc', '', false, false)]
    local procedure OnAfterReleaseSalesDocSubscriber(VAR SalesHeader: Record "Sales Header"; PreviewMode: Boolean; LinesWereModified: Boolean);
    var
        Customer: Record Customer;
    begin
        if SalesHeader.Status <> SalesHeader.Status::Released then
            exit;

        Customer.Get(SalesHeader."Sell-to Customer No.");
        Customer.RewardPoints += 1; // Add a point for each new sales order 
        Customer.Modify();
    end; 

El procedimiento se ejecuta cada vez que se libera un documento de ventas porque el procedimiento está suscrito al evento OnAfterReleaseSalesDoc en la codeunit Liberar documento de ventas.

El procedimiento agrega un punto de recompensa a un cliente por cada nuevo pedido de venta. Aumenta los puntos de recompensa de cada venta a un cliente por cada pedido de venta publicado.