Arquivos Temporários

Foto de Anderson

Aprenda a confeccionar qualquer tipo de relatório em ambiente de rede, por mais complexo que seja, e de processamento rápido com arquivos temporários em Clipper/xBase/Harbour.

Neste estudo de caso será feito um relátorio de devoluções de produto ao fornecedor de um período, c/ fornecedores em ordem alfabética c/ quebra por fornecedor e por ordem de compra.

Tentarei ser o mais inteligível e objetivo possível, acompanhe todo o estudo e você irá entender. Iremos trabalhar, em nosso caso, com três bases de dados do sistema.

Na estrutura deles (para nosso estudo) teriam alguns campos como:

OrdComp.dbf (OC)  Estoque.dbf (ES) Fornec.dbf (FO)
================  ================ ==================
OC________C__8__0 CODPROD__C__5__0 CODFORN___C__2__0
CODPROD___C__5__0 PRODUTO__C__25_0 FORNEC___C__30_0
CODFORN___C__2__0 CODFORN__C__2__0 ...
QTDCOMPRA_N__8__2 QTD______N__6__0
QTDRECEB__N__8__2 VALOR____N__8__2 Index on CODFORN;
QTDDEV____N__8__2 ...                     TO FOCFOR
VALOR_____N__10_2
DCOMPRA___D__8__0 Index on CODPROD;
DRECEB____D__8__0       TO ESCPROD
DDEV______D__8__0 ...
Index on DTOS(DDEV)+OC;
               TO OCDDEV

Em Modelagem de Dados: O OC é um DBF de "vários para um", pois há vários registros (produtos) para uma ordem de compra.

A relação entre OC e ES é de "um para vários", pois em uma ordem de compra há vários produtos.

A relação entre ES e FO é de "vários para um", pois há vários produtos para um só fornecedor.

Atente que as "..." (reticências), em algumas linhas do nosso estudo no programa, indicam que deve haver instruções inerentes ao programa de cada um naquele local.

 

Vamos ao programa:

USE ORDCOMP ALIAS OC SHARED NEW
SET INDEX TO OCDDEV
USE ESTOQUE ALIAS ES SHARED NEW
SET INDEX TO ESCPROD
USE FORNEC ALIAS FO SHARED NEW
SET INDEX TO FOCFOR

Vamos colher dados do usuário p/ o nosso relatório:

DATAI := DATAF := CTOD("")
@ 10,10 SAY "Data inicial:" GET DATAI
@ 11,10 SAY "Data final..:" GET DATAF VALID DATAF >= DATAI
READ
IF LASTKEY() = 27
   // ...
   RETURN
ENDIF

 

Vamos dar um SOFT SEEK para reduzir drasticamente o tempo de nosso relatório.

OC->( DBSEEK( DTOS(DATAI), .T.) )
IF OC->DDEV > DATAF
   ALERT("Não houve devoluções a nenhum fornecedor nesse período!")
   // ...
   RETURN
ENDIF

Precisaremos de um arquivo temporário para as informações que queremos armazenar e mostrar.

Veja que, trabalhando em ambiente de rede não podemos dar um nome fixo como "temp.dbf" por exemplo, pois se dois ou mais usuários pedirem este relatório ao mesmo tempo o DBCREATE() não criará um arquivo que já existe e o programa irá, no mínimo (dependendo de cada caso), duplicar as informações no temporário e bagunçar todo o relatório. Teremos, então, que criar um nome mutante para este temporário... observe:

TEMP    := "TEMP"+SUBSTR( TIME(), 4, 2 )+SUBSTR( TIME(), 7, 2 )
TEMPNTX := "NTX" +SUBSTR( TIME(), 4, 2 )+SUBSTR( TIME(), 7, 2 )

 

As variáveis TEMP e TEMPNTX guardam o nome do temporário e do seu NTX. Depois temos a "&" e/ou os "()", para estrair esses nomes, dependendo da sintaxe do comando/função.

*** Criação do temporário ***
aDBF := {}
aADD( aDBF, {"OC",      "C",  8, 0} )
aADD( aDBF, {"CODPROD", "C",  5, 0} )
aADD( aDBF, {"PRODUTO", "C", 25, 0} )
aADD( aDBF, {"CODFORN", "C",  2, 0} )
aADD( aDBF, {"FORNEC",  "C", 30, 0} )
aADD( aDBF, {"QTDRECEB","N",  8, 2} )
aADD( aDBF, {"QTDDEV",  "N",  8, 2} )
aADD( aDBF, {"VALOR",   "N", 10, 2} )
aADD( aDBF, {"DCOMPRA", "D",  8, 0} )
aADD( aDBF, {"DRECEB",  "D",  8, 0} )
aADD( aDBF, {"DDEV",    "D",  8, 0} )
DBCREATE( &TEMP, aDBF )

 

Está criado o nosso temporário...

Abriremos o nosso arquivo desta forma:

USE (TEMP) ALIAS TMP EXCLUSIVE NEW INDEX ON FORNEC+OC+PRODUTO TO (TEMPNTX)

 

Vamos preencher as informações necessárias em nosso "temp" agora...

DO WHILE DDEV <= DATAF

 

Vamos mover o ponteiro de registro das outras áreas p/ que todas entrem de acordo.

   ES->( DBSEEK(OC->CODPROD) )
   FO->( DBSEEK(OC->CODFORN) )

Agora preencher as informações do temporário...

   TMP->OC       := OC->OC
   TMP->CODPROD  := OC->CODPROD
   TMP->PRODUTO  := ES->PRODUTO
   TMP->CODFORN  := OC->CODFORN
   TMP->FORNEC   := FO->FORNEC
   TMP->QTDRECEB := OC->QTDRECEB
   TMP->QTDDEV   := OC->QTDDEV
   TMP->VALOR    := OC->QTDCOMPRA/OC->VALOR
   TMP->DCOMPRA  := OC->DCOMPRA
   TMP->DRECEB   := OC->DRECEB
   TMP->DDEV     := OC->DDEV
   OC->( DBSKIP() )
ENDDO
TMP->( DBCOMMIT() )

Agora vamos ao relatório propriamente dito!

TMP->( DBGOTOP() )
cFOR := TMP->FORNEC
cOC  := TMP->OC
LL   := 100
LP   := 60

 

Substitua pela variável do número de linhas/página da impressora atualmente configurada, caso seu sistema possua configuração múltipla de impressora.

DO WHILE !TMP->( EOF() )
   IF LL >= LP //Quebra de página
      LL := 0
      ...
      @ LL++,00 SAY REPLI("-",80)
      @ LL++,00 SAY "Fornecedor Código"
      @ LL++,00 SAY " Ord. Compra Data de Compra, Receb. e Devolucao"
      @ LL++,00 SAY " Produto Cód. Qtd.Rec. Qtd.Dev Dev.% Dev.$"
      @ LL++,00 SAY REPLI("-",80)
      @ LL++,00 SAY cFOR+" "+TMP->CODFORN
      @ LL++,05 SAY cOC+" "+DTOC(TMP->DCOMPRA)+", "+DTOC(TMP->DRECEB)+", "+DTOC(TMP->DDEV)
      @ LL,10   SAY TMP->PRODUTO
      @ LL,36   SAY TMP->CODPROD
      @ LL,42   SAY TMP->QTDRECEB
      @ LL,51   SAY TMP->QTDDEV
      DEVp := (TMP->QTDDEV*100)/QTDREC
      DEVv := TMP->QTDDEV*TMP->VALOR
      @ LL,60   SAY DEVp PICTURE "@R 999.99%"
      @ LL++,68 SAY DEVv PICTURE "99999.99"
      TMP->( DBSKIP() )
   ENDIF
   cFOR := TMP->FORNEC
   cOC  := TMP->OC
   IF cFOR # TMP->FORNEC
      cFOR := TMP->FORNEC
      cOC  := TMP->OC
      @ LL++,00 SAY cFOR+" "+TMP->CODFORN
      @ LL++,05 SAY cOC+" "+DTOC(TMP->DCOMPRA)+", "+DTOC(TMP->DRECEB)+", "+DTOC(TMP->DDEV)
   ENDIF
   IF cOC # TMP->OC
      cOC := TMP->OC
      @ LL++,05 SAY cOC+" "+DTOC(TMP->DCOMPRA)+", "+DTOC(TMP->DRECEB)+", "+DTOC(TMP->DDEV)
   ENDIF
   @ LL,10 SAY TMP->PRODUTO
   @ LL,36 SAY TMP->CODPROD
   @ LL,42 SAY TMP->QTDRECEB
   @ LL,51 SAY TMP->QTDDEV
   DEVp := (TMP->QTDDEV*100)/QTDREC
   DEVv := TMP->QTDDEV*TMP->VALOR
   @ LL,60   SAY DEVp PICTURE "@R 999.99%"
   @ LL++,68 SAY DEVv PICTURE "99999.99"
   TMP->( DBSKIP() )
ENDDO

 

Observe que o arquivo temporário deverá ser apagado no final do programa, caso contrário com o tempo a capacidade de registros de arquivos da FAT (tabela de alocação de arquivos) estourará e nenhum outro arquivo poderá ser criado neste diretório e destarte ocasionará um erro fatal.

TMP->( DBCLOSEAREA() ) //Deve-se fechar o arquivo antes de apagá-lo
TEMP    += ".DBF"
TEMPNTX += ".NTX"
FERASE( TEMP )
FERASE( TEMPNTX )
RETURN
*------------------------------

 

Bem, aí está o estudo completo! Espero que tenha gostado. Vamos debater o assunto? Poste seu comentário.

Total votes: 0