Share via


Criar regras para o Assistente de otimização

Este artigo explica como criar novas regras para o Assistente de otimização. Por exemplo, pode criar uma nova regra que identifique quais os casos de Pedidos de Cotação (RFQ) que têm um título vazio. Utilizar títulos em casos torna-os facilmente identificáveis e pesquisáveis. Embora muito simples, este exemplo mostra o que pode ser conseguido com regras de otimização.

Uma regra é uma verificação dos dados da aplicação. Se a condição que a regra avalia for cumprida, são criadas oportunidades para otimizar processos ou melhorar os dados. As oportunidades podem ser aproveitadas e, opcionalmente, o impacto das ações pode ser medido.

Para criar uma nova regra para o Assistente de otimização, adicione uma nova classe que expanda a classe abstrata SelfHealingRule, implementa a interface DiagnosticsRule e é decorada com o atributo DiagnosticRule. A classe também tem de ter um método decorado com o atributo DiagnosticsRuleSubscription. Por convenção, isso é feito com o método opportunityTitle, que será discutido mais adiante. Esta nova classe pode ser adicionada a um modelo personalizado com uma dependência do modelo SelfHealingRules. No exemplo seguinte, a regra que está a ser implementada chama-se RFQTitleSelfHealingRule.

[DiagnosticsRule] 
public final class RFQTitleSelfHealingRule extends SelfHealingRule implements IDiagnosticsRule 
{ 
… 
} 

A classe abstrata SelfHealingRule tem métodos abstratos que têm de ser implementados em classes que herdam. O núcleo é o método de avaliação, que devolve uma lista das oportunidades identificadas pela regra. As oportunidades podem ser por entidade legal ou podem aplicar-se a todo o sistema.

protected List evaluate() 
{ 
    List results = new List(Types::Record); 
    
    DataArea dataArea; 

    while select id from dataArea 
        where !dataArea.isVirtual 
    { 
        changecompany(dataArea.id) 
        { 
            container result = this.findRFQCasesWithEmptyTitle(); 

            if (conLen(result) > 0) 
            { 
                SelfHealingOpportunity opportunity = this.getOpportunityForCompany(dataArea.Id); 
                opportunity.EvaluationState = SelfHealingEvaluationState::Evaluated; 
                opportunity.Data = result; 
                opportunity.OpportunityDate = DateTimeUtil::utcNow(); 
                
                results.addEnd(opportunity); 
            } 
        } 
    } 
    
    return results; 
} 

O método mostrado efetua um ciclo sobre as empresas e seleciona casos de RFQ com títulos vazios no método findRFQCasesWithEmptyTitle. Se pelo menos um desses casos for encontrado, será criada uma oportunidade específica da empresa com o método getOpportunityForCompany. Note que o campo Dados na tabela SelfHealingOpportunity é do tipo Contentor, podendo, portanto, conter quaisquer dados relevantes para a lógica específica desta regra. Definir OpportunityDate com o carimbo de data/hora atual regista a hora da última avaliação da oportunidade.

As oportunidades também podem ser transversais à empresa. Neste caso, o ciclo sobre as empresas não é necessário e a oportunidade deve ser criada com o método getOpportunityAcrossCompanies.

O código seguinte mostra o método findRFQCasesWithEmptyTitle, que devolve os IDs dos casos de RFQ que têm títulos vazios.

private container findRFQCasesWithEmptyTitle() 
{ 
    container result; 

    PurchRFQCaseTable rfqCase; 
    while select RFQCaseId from rfqCase 
        where rfqCase.Name == '' 
    { 
        result += rfqCase.RFQCaseId; 
    } 
    
    return result; 
} 

Mais dois métodos que têm de ser implementados são opportunityTitle e opportunityDetails. O primeiro devolve um título curto para a oportunidade, o último devolve uma descrição detalhada da oportunidade, que também pode incluir dados.

O título devolvido por opportunityTle aparece na coluna Oportunidade de otimização na área de trabalho do Assistente de otimização. Também aparece como o cabeçalho do painel lateral, mostrando mais informações sobre a oportunidade. Por convenção, este método é decorado com o atributo DiagnosticRuleSubscription, que utiliza os seguintes argumentos:

  • Área de diagnóstico — Uma enumeração do tipo DiagnosticArea que descreve a área da aplicação a que a regra pertence, tal como DiagnosticArea::SCM.

  • Nome da regra — Uma cadeia com o nome da regra. Isto aparecerá na coluna Nome da regra no formulário Regra de validação do diagnóstico (DiagnosticsValidationRuleMaintain).

  • Frequência de execução — Uma enumeração do tipo DiagnosticRunFrequency que descreve a frequência com que a regra deve ser executada, como DiagnosticRunFrequency::Daily.

  • Descrição da regra — Uma cadeia com uma descrição mais detalhada da regra. Isto aparecerá na coluna Descrição da regra no formulário Regra de validação do diagnóstico (DiagnosticsValidationRuleMaintain).

Nota

O atributo DiagnosticRuleSubscription é necessário para que a regra funcione. Normalmente é utilizado em opportunityTitle, mas pode decorar qualquer método da classe.

Segue-se um exemplo de implementação. São utilizadas cadeias em bruto para maior simplicidade, mas uma implementação correta requer etiquetas.

[DiagnosticsRuleSubscription(DiagnosticsArea::SCM, 
                             'Assign titles to Request for Quotation cases', 
                             DiagnosticsRunFrequency::Daily,  
                             'This rule detects Requests for Quotation with empty titles.')] 
public str opportunityTitle() 
{ 
    return 'Assign titles to Request for Quotation cases'; 
} 

A descrição devolvida por opportunityDetails aparece no painel lateral, mostrando mais informações sobre a oportunidade. Isto requer o argumento SelfHealingOpportunity, que é o campo Dados que pode ser utilizado para fornecer mais detalhes sobre a oportunidade. No exemplo, o método devolve os IDs dos casos de RFQ com um título vazio.

public str opportunityDetails(SelfHealingOpportunity _opportunity) 
{ 
    str details = ''; 
    container opportunityData = _opportunity.Data; 
    int affectedRFQCasesCount = conLen(opportunityData); 

    if (affectedRFQCasesCount != 0) 
    { 
        details = 'The following Request for Quotation cases have an empty title:\n'; 
        for (int i = 1; i <= affectedRFQCasesCount ; i++) 
        { 
            PurchRFQCaseId rfqCaseId = conPeek(opportunityData, i); 
            details += rfqCaseId + '\n'; 
        } 
    } 

    return details; 
}

Os dois métodos abstratos restantes para implementação são provideHealingAction e securityMenuItem.

provideHealingAction devolve true se for fornecida uma ação de reparação, caso contrário devolve false. Se for devolvido verdadeiro, o método performAction tem de ser implementado ou será gerado um erro. O método performAction requer um argumento SelfHealingOpportunity, no qual os dados podem ser utilizados para a ação. No exemplo, a ação abre PurchRFQCaseTableListPage para correção manual.

public boolean providesHealingAction() 
{ 
    return true; 
} 

protected void performAction(SelfHealingOpportunity _opportunity) 
{ 
    new MenuFunction(menuItemDisplayStr(PurchRFQCaseTableListPage), MenuItemType::Display).run(); 
} 

Dependendo das especificidades da regra, pode ser possível tomar uma ação automática utilizando os dados da oportunidade. Neste exemplo, o sistema poderia gerar títulos para casos de RFQ automaticamente.

securityMenuItem devolve o nome de um item do menu de ação, de modo que a regra só seja visível a utilizadores que possam aceder ao item do menu de ação. A segurança pode exigir que regras e oportunidades específicas sejam acessíveis apenas a utilizadores autorizados. No exemplo, apenas utilizadores com acesso a PurchRFQCaseTitleAction podem ver a oportunidade. Note que este item do menu de ação foi criado para este exemplo e foi adicionado como um ponto de entrada para o privilégio de segurança PurchRFQCaseTableMaintain.

Nota

O item de menu deve ser um item do menu de ação para que a segurança funcione corretamente. Outros tipos de itens de menu, tais como Apresentar itens de menu não funcionarão corretamente.

public MenuName securityMenuItem() 
{ 
    return menuItemActionStr(PurchRFQCaseTitleAction); 
}

Depois de compilada a regra, execute o trabalho seguinte para ser apresentado na interface do utilizador (IU).

class ScanNewRulesJob 
{         
    public static void main(Args _args) 
    {         
        SysExtensionCache::clearAllScopes(); 
        var controller = new DiagnosticsRuleController(); 
        controller.runOperation(); 
    } 
} 

A regra será apresentada no formulário Regra de validação de diagnóstico, disponível a partir de Administração do sistema>Tarefas periódicas>Manter regra de validação de diagnóstico. Para a regra ser avaliada, aceda a Administração do sistema>Tarefas periódicas>Agendar regra de validação de diagnóstico e selecione a frequência da regra, como Diária. Clique em OK. Aceda a Administração do sistema>Assistente de otimização para ver a nova oportunidade.

O exemplo seguinte é um fragmento de código com o esqueleto de uma regra, incluindo todos os métodos e atributos necessários. Ajuda-o a começar a escrever novas regras. As etiquetas e os itens do menu de ação que são utilizados no exemplo são utilizados apenas para fins de demonstração.

[DiagnosticsRuleAttribute]
public final class SkeletonSelfHealingRule extends SelfHealingRule implements IDiagnosticsRule
{
    [DiagnosticsRuleSubscription(DiagnosticsArea::SCM,
                                 "@SkeletonRuleLabels:SkeletonRuleTitle", // Label with the title of the rule
                                 DiagnosticsRunFrequency::Monthly,
                                 "@SkeletonRuleLabels:SkeletonRuleDescription")] // Label with a description of the rule
    public str opportunityTitle()
    {
        // Return a label with the title of the opportunity
        return "@SkeletonRuleLabels:SkeletonOpportunityTitle";
    }

    public str opportunityDetails(SelfHealingOpportunity _opportunity)
    {
        str details = "";

        // Use _opportunity.data to provide details on the opportunity

        return details;
    }

    protected List evaluate()
    {
        List results = new List(Types::Record);

        // Write here the core logic of the rule

        // When creating an opportunity, use:
        //     * this.getOpportunityForCompany() for company specific opportunities
        //     * this.getOpportunityAcrossCompanies() for cross-company opportunities

        return results;
    }

    public boolean providesHealingAction()
    {
        return true;
    }

    protected void performAction(SelfHealingOpportunity _opportunity)
    {
        // Place here the code that performs the healing action

        // To open a form, use the following:
        // new MenuFunction(menuItemDisplayStr(SkeletonRuleDisplayMenuItem), MenuItemType::Display).run();
    }

    public MenuName securityMenuItem()
    {
        return menuItemActionStr(SkeletonRuleActionMenuItem);
    }

}

Para mais informações, veja o breve vídeo do YouTube: Assistente de otimização no Dynamics 365 Finance