Pular para o conteúdo principal

Postagem em destaque

🚀 Oferecendo Serviços Remotos de Desenvolvedor AdvPL e Mais 🖥️

🚀 Oferecendo Serviços Remotos de Desenvolvedor AdvPL e Mais 🖥️ Olá pessoal, Espero que este post encontre todos vocês bem! É com grande entusiasmo que compartilho que estou expandindo meus serviços como Desenvolvedor AdvPL para novos desafios e colaborações. Com mais de duas décadas de experiência sólida, minha jornada profissional tem sido enriquecedora, com a oportunidade de participar de projetos empolgantes ao longo dos anos. Agora, estou ansioso para trazer minha experiência e habilidades para novas equipes e projetos, trabalhando de forma remota. Minha expertise abrange não apenas AdvPL, mas também outras tecnologias-chave, incluindo JS, SQL, Infraestrutura e Otimização de Processos. Acredito que essa combinação de conhecimentos me permite oferecer soluções abrangentes e eficazes para uma variedade de necessidades de desenvolvimento. Acredito que a tecnologia tem o poder de transformar negócios e impulsionar o sucesso, e estou comprometido em ajudar meus clientes a alcançar seu

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 deste blog

BlackTDN :: RLeg ~ Desvendando a Função ParamBox

Para quem precisar desenvolver uma interface de entrada de dados, coisa rápida, e não quer ter aquele trabalhão danado que todos já sabemos, o Protheus tem uma função que ajuda muito, é uma interface semelhante a função Pergunte, porém com muito mais opção de objeto de entrada de dados, alias até colocar o scrollbox desta interface com todos os objetos em outra MsDialog ou Wizard é simples. Vejam o exemplo abaixo, boa sorte! Rleg. //---------------------------------------------------------- // Função exemplo utilizando a função ParamBox() //---------------------------------------------------------- User Function xParamBox() Local aRet := {} Local aParamBox := {} Local aCombo := {"Janeiro","Fevereiro","Março","Abril","Maio","Junho","Julho","Agosto","Setembro","Outubro","Novembro","Dezembro"} Local i := 0 Private cCadastro := "xParambox" // ---------------

BlackTDN :: Customizando a interface de Login no Protheus e by You

A publicação “ BlackTDN :: By You e sua nova tela de login ”  de nosso amigo OBona deu o que falar e, em função disso, esse que a muito não vos escreve resolveu criar uma versão onde será possível personalizar, “por completo”, a tela de login no Protheus/by You. Considerando que OBona já havia “mapeado, identificado e customizado” as imagens peguei-as emprestadas para o exemplo que se segue: O primeiro passo para a customização “total” da interface de login do Protheus/by You será implementar o “Ponto de Entrada” ChgPrDir (Diretório de impressão) . Usaremos esse PE juntamente como programa U_FindMsObject.prg (apresentado pela primeira vez em: Protheus :: ADVPL : The Container : Presents Pandora's box ). Diferente do exemplo proposto por OBona, que substitui, durante o processo de compilação, as imagens padrões do sistema (excluindo-as) por imagens customizadas (com o mesmo nome) este novo exemplo mantém, no RPO, as imagens padrões adicionando novas imagens customizadas que serã

Protheus :: Chamando Funções do Menu Diretamente e sem a Necessidade de Login

Ferne$ perguntou: "...é possível abrir alguma rotina do sistema sem solicitar login ao usuário, como por exemplo a rotina MATA010..." Sim Ferne$, é possível sim. Abaixo um Exemplo para a Chamada à função MATA010 sem a necessidade de Login no sistema. #INCLUDE "PROTHEUS.CH" #INCLUDE "TBICONN.CH" /*/ Funcao: MATA010Ex Data: 30/04/2011 Autor: Marinaldo de Jesus Descricao: Executar a Funcao MATA010 diretamente sem a necessidade de LOGIN no Protheus Sintaxe: 1 ) U_MATA010Ex ( Chamada diretamente na Tela de Entrada do Sistema ) ; ou 2 ) totvsclient.exe -q -p=u_MATA010Ex -a=01;01 -c=rnp_local -e=rnp -m -l ( Chamada Via Linha de Comando ) /*/ User Function MATA010Ex( cEmpFil ) Local aEmpFil Local bWindowInit := { || __Execute( "MATA010()" , "xxxxxxxxxxxxxxxxxxxx" , "MATA010" , "SIGAFAT" , "SIGAFAT", 1 , .T. ) } Local cEmp Local cFil Local cMod Local cModName := "SIGAFAT" DEFA