Performance em formulários

Caros,
Estou em um projeto onde existem diversas filiais e os funcionários da matriz fazem tudo por uma determinada empresa, ou seja, usamos muitos formulários com o CrossCompany habilitado, também com métodos display e etc… tudo que torna um formulário demorado!

Tendo em vista este problema, comecei uma saga para tentar melhorar a performance e logo no inicio eu percebi que se eu limitasse o tamanho do grid exibido, o formulário melhorava drasticamente sua performance, ou seja, ao invés de deixar o grid com tamanho Automático, eu coloquei 350px e o que antes levava quase 15 segundos para abrir, passou a abrir em 9 segundos e as vezes 10, a melhoria foi notada muito facilmente!

Legal, até ai já tinha melhorado bastante, mas foi o suficiente para ver que o problema era em relação a “renderização” dos grids, e sendo assim, era ali que devia trabalhar!

Depois disso, estudando o comportamento das Grids, eu vi o método autoSizeColumns, que quando false, trazia uma performance melhor ainda, ao formulário que levava 15 segundos, passou a levar 4 ou 5 para abrir!

Logo em seguida, alguns usuários passaram a reclamar que quando tentavam abrir o formulário, o ax estava fechando, e percebi que devido as diferenças de instâncias (versão do ax e também do client) era gerado uma exceção, foi então que adicionei o código para verificar se o método estava implementado.

Em resumo, o que deve ser feito:
Formulário -> Grid -> Propriedade AutoDeclaration = yes;
Formulário -> Método init:

1
2
3
4
5
6
7
8
9
10
11
public void init()
{
    ;
    super();
//PICHLER - improve performance - BEGIN
    if ( new SysDictClass(classNum(FormGridControl)).hasObjectMethod(identifierStr(autoSizeColumns)) )
    {
        OverviewGrid.autoSizeColumns(false);
    }
//PICHLER - improve performance - END
}

Pronto, agora pode colocar isso em todos os formulários! Se alguém quiser fazer isso para todos, sobrescrevam o método init da classe SysSetupFormRun, e adicionem o código, mas ai lembrem-se que vocês nunca saberão o nome da grid, ou seja, algumas validações serão necessárias!

Abraço,
Pichler





Destacando diferenças na importação(XPO)!

A convite do nosso amigo Pichler, gostaria de compartilhar com vocês uma ferramenta  que desenvolvi.  Essa ferramenta visa facilitar nosso trabalho quando precisamos avaliar e realizar o merge ao importar um XPO.

Um dos passos ao se  importar um XPO é identificar quais objetos nele contidos são realmente diferentes dos atuais.

Hoje o Dynamics AX destaca somente se o objeto já existe, trazendo seu nome em negrito,  mas não informa se existem diferenças. Para isso o desenvolvedor é obrigado a navegar objeto a  objeto, na tela de importação e  executar a função “comparar”.

A ferramenta aqui apresentada, marca com a tag “<DIFF>” os objetos que possuem diferenças, o que elimina a necessidade de verificar todos os objetos.

O Projeto completo se encontra aqui.

Forte Abraço,

Denis Ribeiro





Visualizar valores de um container

Continuando a série “Revirando meus jobs”…

Uma funcionalidade simples, mas muito legal para trabalhar com containers é o método “conView” da classe Global. Com ela podemos visualizar valores de um container em diversos pontos de um processo, etiquetando cada janela de acordo com um determinado lugar da rotina. Isso é muito útil quando estamos criando métodos que recebem ou processam container de alguma forma, e queremos ver os valores passados, os valores processados e/ou os valores retornado por um ou mais container.

Para exemplificar, segue o seguinte job:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
static void Teste_conView(Args _args)
{
    container con = [1,2,3,4,5];
 
    Integer  integer;
    Counter  counter = 1;
    ;
 
    conView(con,"Antes");
 
    while(counter <= conlen(con))
    {
        integer = conpeek(con,counter);
        con = conpoke(con,counter,integer * 2);
 
        counter++;
    }
 
    conView(con, "Depois");
}

Esta é uma boa alternativa para situações que precisamos debugar para verificar os valores contidos em um container.

Abs,
Anderson Joyle





Calcular impostos das ordens de venda

Ola a todos,
Estava revirando meus jobs hoje e encontrei um que pode ser útil para alguns que ainda sofrem na hora de calcular os impostos de uma ordem de venda em aberto. Para isso, vamos usar a classe SalesTotals.

Acredito que ela seja bem familiar para aqueles que geralmente customizam o modulo de contas a receber no AX. Mas para os que ainda não a conhecem: a classe SalesTotals é responsavel pelos calculos dos totais de uma ordem de venda. Atraves dela são calculados os totais de encargos, peso, volume, quantidade, frete, seguro e etc.

Voltando ao nosso assunto…
Com a classe SalesTotals conseguimos tambem obter os valores de impostos que serão lançados para uma ordem de venda. Vamos analisar o código abaixo:

static void Teste_SalesTotals(Args _args)
{
    // Localiza a ordem de venda e passa o buffer preenchido para o método construct
    SalesTable      salesTable = SalesTable::find("OV_00172494");
    SalesTotals     salesTotals = SalesTotals::construct(salesTable);
 
    TmpTaxWorkTrans tmpTaxWorkTrans;
    ;
 
    // Atribui o retorno do método .tax().tmpTaxWorkTrans() para a tabela temporária
    tmpTaxWorkTrans.setTmpData(salesTotals.tax().tmpTaxWorkTrans());
 
    while
    select tmpTaxWorkTrans
        index TaxCodeIdx
    {
        info(strfmt("Código do imposto: %1 | Valor: %2",tmpTaxWorkTrans.TaxCode,tmpTaxWorkTrans.SourceTaxAmountCur));
    }
}

Passamos para o método construct da classe SalesTotals o table buffer da ordem de venda que queremos calcular os impostos. Este método contem 6 parametros, mas gostaria de destacar apenas 2. O primeiro, como já disse, trata-se do table buffer da ordem de venda. O segundo especifica a quantidade da atualização que gostariamos de calcular os impostos. Caso uma ordem de venda tenha 10 itens, mas temos a intenção de faturar apenas 2 itens, podemos especificar isso para a classe passando como parametro umas das opções do base enum SalesUpdate(Tudo, Separado, Entregar agora ou Guia de remessa).

Depois de instanciar nosso objeto, é preciso chamar o método salesTotals.tax().tmpTaxWorkTrans() e atribuir o seu retorno para uma variavel da tabela TmpTaxWorkTrans.

Pronto. Agora você tem uma tabela temporária preenchida com todos os impostos pertinentes aquela ordem de venda. Basta selecionar os registros de acordo com sua necessidade.

Abs,
Anderson Joyle





O propósito do campo RecVersion

Greetings,
Gostaria de discutir um pouco aqui a funcionalidade do campo RecVersion. Desde que comecei no mundo AX vejo este campo em todas as tabelas, mas nunca me dei conta do seu proposito.

O conceito é um tanto simples:
Como é de conhecimento de todos, toda tabela criada no AX “ganha” automaticamente o campo “RecVersion”. Este campo é preenchido com o valor “1” no novo registro criado, e é atualizado para um número aleatório toda vez que fazemos uma seleção do registro para atualização usando a palavra-chave “forUpdate”. Quando o registro é atualizado(usando os métodos update() ou doUpdate()), o kernel irá verificar se o recVersion original daquele registro é o mesmo que consta no banco de dados. Caso seja, significa que o registro não foi modificado por outro processo, e a atualização pode prosseguir. Caso contrário, será lançada uma exception do tipo “UpdateConflict”.

Veja o código abaixo:

static void Teste_RecVersion(Args _args)
{
    CustTable custTable;
    ;
 
    ttsbegin;
    select forUpdate custTable
        where custTable.AccountNum == "00001";
 
    print custTable.orig().recVersion;
 
    custTable.CreditMax = 1000;
    custTable.update();
    ttscommit;
 
    print custTable.recVersion;
    pause;
}

Ao executa-lo, o código irá imprimir o recVersion do registro original (recuperado pelo método orig()) e o novo recVersion criado apos a chamada da instrução “forUpdate”.

Usando um exemplo mais claro, vamos imaginar que um processo “A” esteja em execução e seleciona um registro da “CustTable” para atualizar o limite de credito de um cliente:

Registro original:

AccountNum Name CreditMax recVersion
00001 Cliente para teste 500 5622

.

. (processo de calculo do novo limite de crédito)

.

Após update:

AccountNum Name CreditMax recVersion
00001 Cliente para teste 1000 68413

 

No momento que é feito o “select forUpdate” o Ax criou um novo número de versão do registro, neste caso o número 68413. Ao chamarmos o método de atualização, será verificado se a versão original do registro continua com o número 5622. Caso não esteja, significa que o registro foi selecionado por um processo “B” enquanto o processo “A” estava ainda calculando o novo limite de crédito. Caso isso acontença, será lançado uma exceção do tipo “UpdateConflict”. Caso contrário, a atualização segue normalmente.

Espero que tenham gostado.

Abs,
Anderson Joyle





Tags / Categorias

RSS



Arquivo

Dynamics Community