Pular para o conteúdo principal

Postagem em destaque

BlackTDN :: Previsão de Horas para Customizações em ERP TOTVS

_Créditos da imagem: Gerada com auxílio do ChatGPT_ --- # **Previsão de Horas para Customizações em ERP TOTVS: Uma Abordagem Baseada em Fatores de Complexidade** No universo de customizações para o ERP da TOTVS, uma das etapas mais desafiadoras é a estimativa precisa do esforço necessário para o desenvolvimento. Muitas vezes, projetos aparentemente simples podem se tornar complexos devido a fatores como dificuldade de acesso ao ambiente ou falta de conhecimento da regra de negócio. Por isso, criamos uma metodologia de cálculo baseada em fatores de ajuste para tornar as estimativas mais precisas e confiáveis. ## **Por que uma boa estimativa é essencial?** Um orçamento mal calculado pode impactar diretamente o cronograma, os custos e até a qualidade da entrega. No caso de projetos relacionados ao ERP TOTVS, onde cada customização está ligada a regras de negócios específicas e a um ambiente muitas vezes complexo, subestimar ou superestimar o tempo necessário pode gerar problemas sign

Protheus :: Otimizando o Relatório FINR550 ( Razonete de Contas Correntes )

Mais uma vez, e a pedido de minha querida amiga Carla Soneta, tive a missão de tentar otimizar o programa FINR550 que gera o relatório Razonete de Contas Correntes. A missão pareceu-me um desafio e aceitei (principalmente por não ser a minha área de negócios). Para que isso fosse possível primeiro eu precisaria do original do FINR550.prx mais atual (uma coisa boa, a Totvs/Microsiga fornece os fontes dos relatórios). Com o FINR550.prx em mãos começou a análise para verificar como otimizá-lo sem alterar sua lógica, estrutura e regras. Pude identificar, Considerando que o cliente que solicitou a otimização utiliza o SGBD DB2 e que possui a "Localização" apenas para o País Brasil, os seguintes pontos:
  1. Chamadas de funções desnecesárias;
  2. Resolver xFilial();
  3. Prefixar os campos e funções de db com seus respectivos Alias;
  4. Resolver "Localização";
  5. Resolver compilação condicional;
  6. Retirar parte do código específica para CodeBase;
  7. Armazenar retorno de funções em variáveis locais e reaproveitá-las quando necessário;
  8. Substituir a chamada a MsSeek() por dbSeek(); e
  9. Retirar a parte de relatório personalizável (tReport).

Vamos ao que interessa:

1. Chamadas de funções desnecesárias
Notei que o código original possuia várias chamadas a dbSelectArea(), xFilial(), dbSetOrder(), etc dentro do laço While/End While. Sendo assim elas foram retiradas. E tratamento de campos e funções de db efetuados conforme item 3.

Notei que chamavam Abs() várias vezes para um mesmo valor, então o número de chamadas a Abs() foi reduzido armazenando o conteúdo em uma variável conforme ítem 7.

Pude verificar que xFilial() era usada dentro de Laço. Então a chamada foi retirada do laço e xFilial() foi resolvida conforme ítem 2.


2. Resolver xFilial()
xFilial() é uma função em Advpl() para retornar a filial correte para uma determinada tabela conforme modo de acesso definido no dicionário de Tabelas ( o SX2). Se a Tabela estiver compartilhada entre filiais xFilial() retornará brancos, caso contrário, retornará a Filial armazenada na variável de ambiente setada com o conteúdo da filial correte. É uma péssima prática resolver xFilial() dentro de um laço, seja ele qual for ( While, For, etc.). Então para cada alias em que xFilial() precisava ser resolvido criei uma variável para esse fim e usei variável no lugar de xFilial como em:

Local cSA1Filial := xFilial("SA1")
Local cSA2Filial := xFilial("SA2")
Local cSE1Filial := xFilial("SE1")
Local cSE2Filial := xFilial("SE2")
Local cSE5Filial := xFilial("SE5")
Local cSX5Filial := xFilial("SX5")

e Depois usando:

While SE1->( !Eof() )

If mv_par18 == 1 // Seleciona clientes por conta contabil
SA1->( dbSeek(cSA1Filial+SE1->(E1_CLIENTE+E1_LOJA) ) )
If SA1->( A1_CONTA <> mv_par20 )
SE1->( dbSkip() )
Loop
Endif
Endif

ao ivés de

If mv_par18 == 1 .And. !(TcGetDb() $ "MSSQL/MSSQL7/ORACLE") // Seleciona clientes por conta contabil
dbSelectArea("SA1")
MsSeek(xFilial()+SE1->E1_CLIENTE+SE1->E1_LOJA)
If SA1->A1_CONTA <>A1_CONTA > mv_par20
dbSelectArea("SE1")
dbSkip()
Loop
Endif
Endif

3. Prefixar os campos e funções de db com seus respectivos Alias

Para evitar chamadas desnecessárias à função dbSelectArea() prefixei todos os campos com seus respectivos Alias.

Onde estava, por exemplo:

dbSelectArea("SE1")

IF E1_TIPO $ MVRECANT

dbSkip()

ENDIF

Alterei para

IF SE1->E1_TIPO $ MVRECANT

SE1->( dbSkip() )

EndIF

Onde estava:

dbSelectArea("SE1")

dbSetOrder(1)

Alterei para:

SE1->( dbSetOrder(1) )

Onde estava:

dbSelectArea("SE1")

...

dbSkip()

Alterei para:

SE1->( dbSkip() )

e assim por diante.


4. Resolver "Localização"

Para que testar se o País Local é o Brasil se sei que o código só será utilizado aqui. Então para deixa-lo mais enxuto e evitar testes desnecessários, retirei toda parte do código que não se referiam ao cPaisLoc == "BRA".

5. Resolver compilação condicional

Sabendo que o SGBD a ser utilizado seria o DB2, toda parte do código específica para CodeBase e/ou AS400() ou outro SGBD foi retirada.

6. Retirar parte do código específica para CodeBase

Idem ao item 5 e considerando que a parte retirada estava diretamente relacionada ao tratamento já dado à "View" retornada pela "Query".

7. Armazenar retorno de funções em variáveis locais e reaproveitá-las quando necessário
Tinha algo como:

nSaldoAtu -= ABS(cNomeArq->VALOR)
nTotDeb += ABS(cNomeArq->VALOR)
nTotDebG += ABS(cNomeArq->VALOR)
nSalAtuG -= ABS(cNomeArq->VALOR)

Oberve que ABS(cNomeArq->VALOR) era chamada 4 vezes para retornar o valor absoluto de um mesmo campo e armazena-la em variáveis diferentes. Imagine isso dentro de um Laço executado 1000 vezes. ABS seria executada 4000 vezes desnecessáriamente. Para solucionar o problema fiz o seguinte:

nABSValor := Abs(cNomeArq->VALOR)
nSaldoAtu -= nABSValor
nTotDeb += nABSValor
nTotDebG += nABSValor
nSalAtuG -= nABSValor
Observe que agora Abs(), se o laço for executado 1000 vezes só será executado 1000 vezes.

8. Substituir a chamada a MsSeek() por dbSeek(); e

MsSeek() é uma função "bufferizada" criada em Advpl para evitar o reposicionamento do "Ponteiro" do Banco de Dados quando este já estiver posicionado na chave que se deseja procurar. É útil, por exemplo, se usou a função de pesquisa dbSeek() para pesquisar e depois quer saber se o registro está posicionado evitando ter que pesquisa-lo novamente. Ai sim MsSeek() é útil, caso contrário é um desperdício, uma vez que MsSeek() faz vários tratamentos para verificar se a chave atual é a que procura e, se não for, irá chamar dbSeek() para posicionar.

9. Retirar a parte de relatório personalizável (tReport).

Considerando que o cliente não utiliza o FINR55o personalizável, a parte do código foi retirada para facilitar a manutenção do código.

Bem, é isso o que tinha a dizer sobre otimização do códgo FINR550 (baseado no código padrão). Para consultar na íntegra as alterações feitas no código e poder comparar com o original da microsiga utilizado como base para a otimização clique aqui

Utilize o apdiff ou outra ferramenta para comparar os códigos e visualizar as alterações.

Obs.: Sempre que for otimizar um código do padrão obtenha a última versão disponível junto a Totvs/Microsiga. Lembrando que a Totvs/Microsigadisponibiliza os fontes de Relatórios.

[]s

иαldσ

Comentários

  1. Boa noite Naldo.

    Muito bom, parabéns.

    Att.,

    Talvane (Arapiraca/AL)

    ResponderExcluir
  2. Bom dia Naldo, teria como voce me enviar o fonte do FINR550 otimizado??

    ResponderExcluir
  3. jfernandocv@gmail.com ou jfcvilela@sistemafieg.org.br

    ResponderExcluir
  4. Boa tarde,

    Teria como me enviar o fonte
    cleberfiscal23@gmail.com

    ResponderExcluir

Postar um comentário

Postagens mais visitadas