Página 16 de 35

Meu modo de trabalho

Enviado: 06 Abr 2020 16:42
por JoséQuintas
Também a título de curiosidade....

Tive que trocar a versão no cliente, durante as alterações....
Ok, sem problemas, apenas confirmei se era melhor cancelar o que estava pela metade, ou terminar e instalar.

E surgiu um problema: o produto estava no MYSQL mas NÃO no DBF.

Cadastrei o código no DBF, entrei na alteração do cadastro, e fui até o final.
Ao terminar, atualizou também esse código equivalente no DBF.
É... se não fosse o DBF não teria problema kkkk
Mas é lógico, NÃO é problema em usar DBF, é porque cometi algum erro, e não gravou no DBF.

Esse problema aconteceu com versão anterior, que estava em uso.
Até revisei na versão atual, mas parece tudo ok.
Por enquanto é aguardar se vai acontecer de novo.

Pois é... trata-se de uma alteração geral, alterar devagar e com cuidado não significa que não acontecem problemas...

Meu modo de trabalho

Enviado: 20 Abr 2020 18:37
por JoséQuintas
NÃO parei com as alterações.
É que agora é tudo com cuidado.
Pedidos, financeiro, boletos, bancos, faturamento, etc. essas coisas.
Usando ao máximo números nos campos chave, e deixando de usar DBF como referência principal.

Meu modo de trabalho

Enviado: 27 Abr 2020 19:30
por JoséQuintas
Mais um relatório simples.
É só um total por fornecedor, do contas a pagar.
Vou começar a alterar ainda, aqui é o fonte atual usando DBF, que está rodando no cliente (se é que algum usa).

Código: Selecionar todos

/*
PFINANRELMAIFOR - RELATORIO DE MAIORES FORNECEDORES
1997.04 José Quintas
*/

#include "inkey.ch"

MEMVAR m_DeAte, m_Datai, m_Dataf, m_Ordem, m_DbfTmp, m_NtxTmp, m_TxtOrdem, m_TxtDeAte, nOpcPrinterType

PROCEDURE pFinanRelMaiFor

   LOCAL  nOpcGeral := 1, m_TxtMenu, m_Temp, mDefault, m_Conf := 2, m_Stru

   PRIVATE m_txtordem := { "Valor (Decresc)", "Fornecedor" }
   PRIVATE m_deate    := 1
   PRIVATE m_datai    := Ctod( "" )
   PRIVATE m_dataf    := Ctod( "" )
   PRIVATE m_txtdeate := { "Todas", "Intervalo" }

   nOpcPrinterType := AppPrinterType()

   IF ! AbreArquivos( "jpcadastro", "jpconfi", "jpempresa", "jpfinan", "jpsenha", "jptabel" )
      RETURN
   ENDIF
   SELECT jpfinan

   m_DbfTmp := MyTempFile( "DBF" )
   m_NtxTmp := MyTempFile( "CDX" )

   m_Stru := { ;
      { "FORNEC",  "C",  6, 0 }, ;
      { "NOME",    "C", 30, 0 }, ;
      { "XXCNPJ",  "C", 18, 0 }, ;
      { "VALOR",   "N", 17, 2 } }
   SELECT 0
   dbCreate( m_DbfTmp, m_Stru )
   USE (m_DbfTmp) EXCLUSIVE NEW ALIAS temp

   mDefault  := LeCnfRel()
   m_ordem   := iif( mDefault[ 1 ] > 2, 1, mDefault[ 1 ] )
   m_txtmenu := Array(5)

   WOpen( 5, 4, 7 + Len( m_txtmenu ), 45, "Opções disponíveis" )

   DO WHILE .T.

      m_txtmenu := { ;
         TxtImprime(), ;
         TxtSalva(), ;
         "Ordem.....: " + m_txtordem[ m_ordem ], ;
         "Datas.....: " + iif( m_DeAte == 1, m_txtdeate[ 1 ], ;
         Dtoc( m_datai ) + " a " + Dtoc( m_dataf ) ), ;
         "Saída.....: " + TxtSaida()[ nOpcPrinterType ] }

      FazAchoice( 7, 5, 6 + Len( m_txtmenu ), 44, m_txtmenu, @nOpcGeral )

      m_Temp := 1
      DO CASE
      CASE LastKey() == K_ESC
         EXIT

      CASE nOpcGeral == m_Temp++
         IF ConfirmaImpressao()
            imprime()
         ENDIF

      CASE nOpcGeral == m_Temp++
         m_conf = 2
         WAchoice( nOpcGeral+6, 25, TxtConf(), @m_conf, TxtSalva() )
         IF m_conf == 1 .AND. LastKey() != K_ESC
            GravaCnfRel( { m_Ordem } )
         ENDIF

      CASE nOpcGeral == m_Temp++
         WAchoice( nOpcGeral + 6, 25, m_txtordem, @m_ordem, "Ordem de Impressão" )

      CASE nOpcGeral == m_Temp++
         DataIntervalo( nOpcGeral + 6, 25, @m_DeAte, @m_Datai, @m_Dataf )

      CASE nOpcGeral == m_Temp
         WAchoice( nOpcGeral + 6, 25, TxtSaida(), @nOpcPrinterType, "Saída" )
         AppPrinterType( nOpcPrinterType )

      ENDCASE
   ENDDO
   WClose()
   CLOSE DATABASES
   fErase(m_DbfTmp)
   fErase(m_NtxTmp)

   RETURN

STATIC FUNCTION imprime()

   LOCAL oPDF, nKey, m_Soma, m_Total

   SELECT Temp
   ZAP
   INDEX ON temp->Fornec TO ( m_NtxTmp )

   SELECT jpfinan
   GOTO TOP
   DO WHILE ! Eof()
      GrafProc()
      IF jpfinan->fiTipLan != "2"
         SKIP
         LOOP
      ENDIF
      IF m_DeAte==2
         IF jpfinan->fiDatEmi < m_Datai .OR. jpfinan->fiDatEmi > m_Dataf
            SKIP
            LOOP
         ENDIF
      ENDIF
      encontra( jpfinan->fiCadastro, "jpcadastro", "numlan" )
      IF ! encontra( jpfinan->fiCadastro, "temp" )
         SELECT temp
         RecAppend()
         REPLACE ;
            temp->Fornec WITH jpfinan->fiCadastro, ;
            Temp->xxCnpj WITH jpcadastro->cdCnpj, ;
            Temp->Nome WITH jpcadastro->cdNome
         RecUnlock()
      ENDIF
      SELECT temp
      RecLock()
      REPLACE Temp->Valor WITH temp->Valor + jpfinan->fiValor
      RecUnlock()
      SELECT jpfinan
      SKIP
   ENDDO

   oPDF := PDFClass():New()
   oPDF:SetType( nOpcPrinterType )
   oPDF:Begin()

   nKey = 0

   oPDF:acHeader := { "", "", "" }
   oPDF:acHeader[ 1 ] := "CONTAS A PAGAR"
   oPDF:acHeader[ 2 ] := "MAIORES FORNECEDORES - Ordem: " + m_txtordem[ m_ordem ]
   IF m_deate == 2
      oPDF:acHeader[ 2 ] += " - Data: " + Dtoc( m_datai ) + " a " + Dtoc( m_dataf )
   ENDIF
   oPDF:acHeader[ 3 ] := "-----------NOME DO FORNECEDOR-----------  -------C.G.C.-------  -----FATURAMENTO----  %TOTAL"

   SELECT Temp
   IF m_Ordem == 1
      INDEX ON -temp->valor TO ( m_NtxTmp )
   ELSE
      INDEX ON temp->nome TO ( m_NtxTmp )
   ENDIF
   SUM temp->Valor TO m_Total
   m_Soma := 0
   GOTO TOP
   DO WHILE nKey != K_ESC .AND. ! Eof()
      grafproc()
      nKey = Inkey()
      oPDF:MaxRowTest()
      oPDF:DrawText( oPDF:nRow, 0, Temp->Nome )
      oPDF:DrawText( oPDF:nRow, 42, Temp->xxCnpj )
      oPDF:DrawText( oPDF:nRow, 64, Temp->Valor, PicVal(14,2) )
      oPDF:DrawText( oPDF:nRow, 86, ( Temp->Valor * 100 / m_Total ), "@E 999.99" )
      m_Soma += temp->Valor
      oPDF:nRow  += 1
      SKIP
   ENDDO
   IF oPDF:nPageNumber != 0
      oPDF:MaxRowTest()
      oPDF:DrawText( oPDF:nRow, 0, "TOTAL IMPRESSO....:" )
      oPDF:DrawText( oPDF:nRow, 64, m_Soma, PicVal(14,2) )
      oPDF:DrawText( oPDF:nRow, 86, ( m_Soma * 100 / m_Total ), "@E 999.99" )
      oPDF:nRow += 1
      oPDF:MaxRowTest()
   ENDIF
   oPDF:End()

   RETURN NIL

Meu modo de trabalho

Enviado: 27 Abr 2020 19:48
por JoséQuintas
pronto.

Código: Selecionar todos

/*
PFINANRELMAIFOR - RELATORIO DE MAIORES FORNECEDORES
1997.04 José Quintas
*/

#include "inkey.ch"

MEMVAR nOpcData, m_Datai, m_Dataf, nOpcOrdem, acTxtOrdem, acTxtData, nOpcPrinterType

PROCEDURE pFinanRelMaiFor

   LOCAL  nOpcGeral := 1, acTxtGeral, m_Temp, mDefault, m_Conf := 2

   PRIVATE acTxtOrdem := { "Valor (Decresc)", "Fornecedor" }
   PRIVATE nOpcData    := 1
   PRIVATE m_datai    := Ctod( "" )
   PRIVATE m_dataf    := Ctod( "" )
   PRIVATE acTxtData := { "Todas", "Intervalo" }

   nOpcPrinterType := AppPrinterType()

   IF ! AbreArquivos( "jpcadastro", "jpconfi", "jpempresa", "jpfinan", "jpsenha", "jptabel" )
      RETURN
   ENDIF
   SELECT jpfinan

   mDefault  := LeCnfRel()
   nOpcOrdem   := iif( mDefault[ 1 ] > 2, 1, mDefault[ 1 ] )
   acTxtGeral := Array(5)

   WOpen( 5, 4, 7 + Len( acTxtGeral ), 45, "Opções disponíveis" )

   DO WHILE .T.

      acTxtGeral := { ;
         TxtImprime(), ;
         TxtSalva(), ;
         "Ordem.....: " + acTxtOrdem[ nOpcOrdem ], ;
         "Datas.....: " + iif( nOpcData == 1, acTxtData[ 1 ], ;
         Dtoc( m_datai ) + " a " + Dtoc( m_dataf ) ), ;
         "Saída.....: " + TxtSaida()[ nOpcPrinterType ] }

      FazAchoice( 7, 5, 6 + Len( acTxtGeral ), 44, acTxtGeral, @nOpcGeral )

      m_Temp := 1
      DO CASE
      CASE LastKey() == K_ESC
         EXIT

      CASE nOpcGeral == m_Temp++
         IF ConfirmaImpressao()
            imprime()
         ENDIF

      CASE nOpcGeral == m_Temp++
         m_conf = 2
         WAchoice( nOpcGeral+6, 25, TxtConf(), @m_conf, TxtSalva() )
         IF m_conf == 1 .AND. LastKey() != K_ESC
            GravaCnfRel( { nOpcOrdem } )
         ENDIF

      CASE nOpcGeral == m_Temp++
         WAchoice( nOpcGeral + 6, 25, acTxtOrdem, @nOpcOrdem, "Ordem de Impressão" )

      CASE nOpcGeral == m_Temp++
         DataIntervalo( nOpcGeral + 6, 25, @nOpcData, @m_Datai, @m_Dataf )

      CASE nOpcGeral == m_Temp
         WAchoice( nOpcGeral + 6, 25, TxtSaida(), @nOpcPrinterType, "Saída" )
         AppPrinterType( nOpcPrinterType )

      ENDCASE
   ENDDO
   WClose()
   CLOSE DATABASES

   RETURN

STATIC FUNCTION imprime()

   LOCAL oPDF, nKey, m_Total
   LOCAL cnSQL := ADOClass():New( AppConexao() )

   oPDF := PDFClass():New()
   oPDF:SetType( nOpcPrinterType )
   oPDF:Begin()
   nKey = 0
   oPDF:acHeader := { "", "", "" }
   oPDF:acHeader[ 1 ] := "CONTAS A PAGAR"
   oPDF:acHeader[ 2 ] := "MAIORES FORNECEDORES - Ordem: " + acTxtOrdem[ nOpcOrdem ]
   IF nOpcData == 2
      oPDF:acHeader[ 2 ] += " - Data: " + Dtoc( m_datai ) + " a " + Dtoc( m_dataf )
   ENDIF
   oPDF:acHeader[ 3 ] := "-----------NOME DO FORNECEDOR-----------  -------C.G.C.-------  -----FATURAMENTO----  %TOTAL"
   WITH OBJECT cnSQL
      :cSQL := "SELECT SUM( FIVALOR ) AS TOTAL, FICADASTRO," + ;
         " JPCADASTRO.CDNOME, JPCADASTRO.CDCNPJ" + ;
         " FROM JPFINAN" + ;
         " LEFT JOIN JPCADASTRO ON JPCADASTRO.IDCADASTRO = JPFINAN.FICADASTRO" + ;
         " WHERE FITIPLAN = '2'"
      IF nOpcData == 2
         :cSQL += " AND FIDATEMI BETWEEN CAST( " + DateSQL( m_Datai ) + " AS DATE )" + ;
            " AND CAST( " + DateSQL( m_Dataf ) + " AS DATE )"
      ENDIF
      :cSQL += " GROUP BY FICADASTRO"
      IF nOpcOrdem == 1
         :cSQL += " ORDER BY TOTAL DESC"
      ELSE
         :cSQL += " ORDER BY CDNOME"
      ENDIF
      :Execute()
      m_Total := 0
      DO WHILE ! :Eof()
         m_Total += :Number( "TOTAL" )
         :MoveNext()
      ENDDO
      :MoveFirst()
      DO WHILE nKey != K_ESC .AND. ! :Eof()
         grafproc()
         nKey = Inkey()
         oPDF:MaxRowTest()
         oPDF:DrawText( oPDF:nRow, 0, :String( "CDNOME", 30 ) )
         oPDF:DrawText( oPDF:nRow, 42, :String( "CDCNPJ", 18 ) )
         oPDF:DrawText( oPDF:nRow, 64, :Number( "TOTAL" ), PicVal(14,2) )
         oPDF:DrawText( oPDF:nRow, 86, ( :Number( "TOTAL" ) * 100 / m_Total ), "@E 999.99" )
         oPDF:nRow  += 1
         :MoveNext()
      ENDDO
      IF oPDF:nPageNumber != 0
         oPDF:MaxRowTest()
         oPDF:DrawText( oPDF:nRow, 0, "TOTAL IMPRESSO....:" )
         oPDF:DrawText( oPDF:nRow, 64, m_Total, PicVal(14,2) )
         oPDF:DrawText( oPDF:nRow, 86, 100, "@E 999.99" )
         oPDF:nRow += 1
         oPDF:MaxRowTest()
      ENDIF
      :CloseRecordset()
   ENDWITH
   oPDF:End()

   RETURN NIL
18 minutos, incluindo dar uma geral no fonte até nos nomes de variáveis.
Acho que tá bom pra um simples.

Meu modo de trabalho

Enviado: 06 Mai 2020 16:01
por JoséQuintas
Uma alteração mais simples, lembrando que é usando minha classe pra ADO.
Na tela do financeiro, mostrando todos os lançamentos referentes ao mesmo pedido do lançamento atual.

Código: Selecionar todos

   IF mIdPedido != 0
      Encontra( StrZero( mIdPedido, 6 ), "jppedido", "pedido" )
      @ mRow+2, 0 SAY "Valor do pedido:" + Transform( jppedido->pdValNot, PicVal(14,2) )
      @ mRow+3, 0 SAY ""
      mRecNo  := RecNo()
      OrdSetFocus( "pedido" )
      SEEK StrZero( mIdPedido, 6 )
      mCol := 1
      DO WHILE Val( jpfinan->fiPedido ) == mIdPedido .AND. Row() < MaxRow()-3 .AND. ! Eof()
         @ Row(), mCol SAY "Lanc." + jpfinan->idFinan + " " + Dtoc( jpfinan->fiDatVen ) + Transform( jpfinan->fiValor, PicVal(14,2) ) + iif( Empty( jpfinan->fiDatPag ), "AB", "PG" )
         IF mCol == 1
            mCol := 55
         ELSE
            mCol := 1
            @ Row()+1, 0 SAY ""
         ENDIF
         SKIP
      ENDDO
      OrdSetFocus( "jpfinan1" )
      GOTO mRecNo
   ENDIF
agora alterado

Código: Selecionar todos

   IF mIdPedido != 0
      WITH OBJECT cnSQL
         :cSQL := "SELECT IDPEDIDO, PDVALNOT, JPFINAN.IDFINAN, JPFINAN.FIDATVEN," + ;
            " JPFINAN.FIDATPAG, JPFINAN.FIVALOR" + ;
            " FROM JPPEDIDO" + ;
            " LEFT JOIN JPFINAN ON JPFINAN.FIPEDIDO = JPPEDIDO.IDPEDIDO" + ;
            " WHERE IDPEDIDO = " + NumberSQL( mIdPedido )
         :Execute()
         @ mRow+2, 0 SAY "Valor do pedido:" + Transform( :Number( "PDVALNOT" ), PicVal(14,2) )
         @ mRow+3, 0 SAY ""
         mCol := 1
         DO WHILE Row() < MaxRow()-3 .AND. ! :Eof()
            @ Row(), mCol SAY "Lanc." + Str( :Number( "IDFINAN" ), 6 ) + " " + ;
               Dtoc( :Date( "FIDATVEN" ) ) + Transform( :Number( "FIVALOR" ), PicVal(14,2) ) + ;
               iif( Empty( :Date( "FIDATPAG" ) ), "AB", "PG" )
            IF mCol == 1
               mCol := 55
            ELSE
               mCol := 1
               @ Row()+1, 0 SAY ""
            ENDIF
            :MoveNext()
         ENDDO
         :CloseRecordset()
      ENDWITH
   ENDIF
Até que o fonte não alterou muito a lógica, mas agora sem DBF.

Meu modo de trabalho

Enviado: 06 Mai 2020 16:26
por JoséQuintas
Aproveitando pra mostrar a mudança em variáveis.
Ficou muito legal.

Código: Selecionar todos

   mIdFinanceiro := ::axKeyValue[ 1 ]
   Encontra( StrZero( mIdFinanceiro, 6 ), "jpfinan", "numlan" )
   WITH OBJECT cnSQL
      :cSQL := "SELECT * FROM JPFINAN WHERE IDFINAN = " + NumberSQL( mIdFinanceiro )
      :Execute()
      mfiDatPag   := :Date( "FIDATPAG" )
      mVlBaixa    := :Number( "FIVALOR" )
      mfiNumDoc   := :String( "FINUMDOC", 9 )
      mfiParcela  := :String( "FIPARCELA", 3 )
      mfiTipDoc   := :String( "FITIPDOC", 6 )
      mIdCadastro := :Number( "FICADASTRO" )
      mfiDatEmi   := :Date( "FIDATEMI" )
      mfiDatVen   := :Date( "FIDATVEN" )
      mfiValor    := :Number( "FIVALOR" )
      mIdPortador := :Number( "FIPORTADOR" )
      mfiDatCan   := :Date( "FIDATCAN" )
      mIdCCusto   := :Number( "FICCUSTO" )
      mIdVendedor := :Number( "FIVENDEDOR" )
      mfiObs      := :String( "FIOBS", 100 )
      mfiNumBan   := :Number( "FINUMBAN" )
      mIdPedido   := :Number( "FIPEDIDO" )
      mIdOperacao := :Number( "FIOPERACAO" )
   ENDWITH
No arquivo/tabela do financeiro, é tudo começando com FI.
Pra variáveis acrescente o prefixo m, no caso desse financeiro mFI.
Mas....
Nas mudanças durante a conversão, alterei tudo que é campo como o campo chave de cada tabela.
Isso facilitou muito no aplicativo em geral.

FICADASTRO, FIPORTADOR, FICCUSTO, FIVENDEDOR, FIPEDIDO, FIOPERACAO
esses agora mudaram para
mIdCadastro, mIdPortador, mIdCCusto, mIdVendedor, mIdPedido, mIdOperacao

Isso no aplicativo, durante o uso.
Nas tabelas seguem como eram antes, exceto terem mudado de caractere para numérico NO MYSQL.

Meu modo de trabalho

Enviado: 07 Mai 2020 01:40
por JoséQuintas
Tava convertendo esta parte:

Código: Selecionar todos

   Encontra( StrZero( mIdFinanceiro, 6 ), "jpfinan", "numlan" )
   IF ! Empty( jpfinan->fiDatPag ) .OR. ! Empty( jpfinan->fiDatCan )
      MsgWarning( "Documento já possui baixa" )
      RETURN NIL
   ENDIF
Aí pensei... porque não...

Código: Selecionar todos

   IF ADORecCount( "JPFINAN", "IDFINAN = " + NumberSQL( midFinanceiro ) + ;
      " AND FIDATPAG IS NULL AND FIDATCAN IS NULL" ) == 0
      MsgWarning( "Documento já possui baixa" )
      RETURN NIL
   ENDIF
Não vou ter o registro atual no MySQL, mas pra não encher de fonte, simplifiquei apenas testando se existe o lançamento sem baixa.
Convém lembrar que na tela vai estar o lançamento, então ele existe.
É uma solução interessante, pra não buscar o lançamento só pra pegar esses dois campos e testar.

Isso não é uma coisa que uma conversão automática, ou RDD faria pra mim.
Devagarzinho, sem pressa, o uso do DBF vai sumindo...

E importante:
A criação da função ADORecCount() foi justamente pra economizar fonte.
São essas "coisinhas" que facilitam, e não o uso de um ou outro tipo de conexão.

Lembram: somos programadores, precisamos considerar que somos nosso cliente e trabalhar mais pra nós... a fim de trabalharmos menos.... rs

E .... fazendo devagar dá pra pensar mais e trabalhar menos...
Se estivesse com pressa de converter tudo, talvez não tivesse pensado nisso.

Meu modo de trabalho

Enviado: 07 Mai 2020 11:44
por JoséQuintas
Mais outra função que criei como quebra-galho, e é interessante.
É uma função simples, pra retornar um campo do SQL.
Aqui um exemplo de uso, antes e depois:

Código: Selecionar todos

         DO CASE
         CASE mfiTipLan == "D"
            OrdSetFocus("jpfinan2") // fiTipLan + fiNumDoc
         CASE mfiTipLan == "B"
            OrdSetFocus("numbanco") // fiNumBan
         OTHERWISE
            OrdSetFocus("numlan") // idFinan
         ENDCASE
         @ 5, 0 SAY "Num. Docto...........:" GET mfiNumDoc PICTURE "@K 999999999" VALID FillZeros( @mfiNumDoc ) WHEN mfiTipLan == "D"
         @ Row(), 35 SAY "Parcela.." GET mfiParcela PICTURE "@K 999" WHEN mfiTipLan == "D" VALID FillZeros( @mfiParcela )
         @ 6, 0 SAY "Num.Bancário.........:" GET mfiNumBan PICTURE "@K 999999" WHEN mfiTipLan == "B"
         @ 7, 0 SAY "Num.Lançamento.......:" GET midFinanceiro   PICTURE "@K 999999" VALID OkNumLanFin( @midFinanceiro ) WHEN ! mfiTipLan $ "DB"
         @ 8, 0 SAY "Valor Original.......:" GET mfiValor    PICTURE PicVal(14,2)
         @ 9, 0 SAY "Juros(+) Descto(-)...:" GET mfiJurDes   PICTURE PicVal(14,2)
         Mensagem( "Digite campos, F9 Pesquisa ESC Sai" )
         READ
         Mensagem()
         IF LastKey() == K_ESC
            EXIT
         ENDIF
         DO CASE
         CASE mfiTipLan == "D"
            SEEK "1" + mfiNumDoc + mfiParcela
            nRecFound := RecNo()
            DO WHILE jpfinan->fiTipLan == "1" .AND. jpfinan->fiNumDoc == mfiNumDoc .AND. jpfinan->fiParcela == mfiParcela .AND. ! Eof()
               nRecFound := RecNo()
               SKIP
            ENDDO
            GOTO (nRecFound)
         CASE mfiTipLan == "B"
            SEEK StrZero( mfiNumBan, 6 )
         OTHERWISE
            SEEK StrZero( midFinanceiro, 6 )
         ENDCASE
         IF Eof()
            MsgWarning( "Documento não cadastrado!" )
            LOOP
         ENDIF
         Encontra( jpfinan->fiCadastro, "jpcadastro", "numlan" )
Primeiro pensar...
o objetivo é encontrar um lançamento no financeiro, podendo ser 3 critérios diferentes.
O que identifica a pesquisa pode variar, mas o resultado é um lançamento, então.... IdFinanceiro

Código: Selecionar todos

         @ 5, 0 SAY "Num. Docto...........:" GET mfiNumDoc PICTURE "@K 999999999" VALID FillZeros( @mfiNumDoc ) WHEN mfiTipLan == "D"
         @ Row(), 35 SAY "Parcela.." GET mfiParcela PICTURE "@K 999" WHEN mfiTipLan == "D" VALID FillZeros( @mfiParcela )
         @ 6, 0 SAY "Num.Bancário.........:" GET mfiNumBan PICTURE "@K 999999" WHEN mfiTipLan == "B"
         @ 7, 0 SAY "Num.Lançamento.......:" GET midFinanceiro   PICTURE "@K 999999" VALID OkNumLanFin( @midFinanceiro ) WHEN ! mfiTipLan $ "DB"
         @ 8, 0 SAY "Valor Original.......:" GET mfiValor    PICTURE PicVal(14,2)
         @ 9, 0 SAY "Juros(+) Descto(-)...:" GET mfiJurDes   PICTURE PicVal(14,2)
         Mensagem( "Digite campos, F9 Pesquisa ESC Sai" )
         READ
         Mensagem()
         IF LastKey() == K_ESC
            EXIT
         ENDIF
         DO CASE
         CASE mfiTipLan == "D"
            nIdFinanceiro := ADOField( "IDFINAN", "N", "JPFINAN", "FITIPLAN = '1'" + ;
               " AND FINUMDOC = " + StringSql( mfiNumDoc ) + " AND FIPARCELA = " + StringSql( mfiParcela ) + ;
               " ORDER BY IDFINAN DESC" )
         CASE mfiTipLan == "B"
            mIdFinanceiro := ADOField( "IDFINAN", "N", "JPFINAN", "FINUMBAN = " + StringSQL( mfiNumBan ) )
         OTHERWISE
            midFinanceiro := ADOField( "IDFINAN", "N", "JPFINAN", "IDFINAN = " + NumberSQL( mIdFinanceiro ) )
         ENDCASE
         IF mIdFinanceiro == 0
            MsgWarning( "Documento não cadastrado!" )
            LOOP
         ENDIF
         Encontra( StrZero( mIdFinanceiro, 6 ), "jpfinan", "numlan" )
         Encontra( jpfinan->fiCadastro, "jpcadastro", "numlan" )
Relativamente simples: seja qual for a pesquisa, retorna a ID do lançamento.
E cada pesquisa usando o que entra na pesquisa.

A função usa o nome do campo, "N" pra identificar que é retorno numérico, a tabela, e o comando SQL.
A identificação de tipo é porque no SQL poderia conter um NULL no campo, então o tipo garante que o retorno vai ser numérico, porque vai converter NULL pra número 0.

A função só precisa combinar os parâmetros.
Numa forma resumida:

ADOField( cCampo, cTipo, cTabela, cCriterio )

"SELECT " + cCampo + " FROM " + cTabela + " WHERE " + cCriterio

É até pouco pra usar função mas... considerando fazer consulta, testar resultado, e até poder usar em IF, a torna interessante.
Comparando com DBF, é como abrir arquivo, posicionar com SEEK, e retornar o campo.

Porque entrou esta parte?
Encontra( StrZero( mIdFinanceiro, 6 ), "jpfinan", "numlan" )

Não dependo mais do DBF pra ESSA pesquisa, mas falta alterar o resto do fonte.
Tudo bem, por enquanto o que importa é reduzir o uso de DBF mas que o fonte continue funcionando.
Melhor alterar aos poucos, pra evitar perder o controle.
Essa parte garante que não vai faltar nada pro resto do fonte.

De quebra, eu poderia acabar com outros índices, e manter somente o índice por ID no DBF !!!
Apenas uma possibilidade, com certeza continuar caminhando pra eliminar o dbf de vez.
A gravação dupla está sendo legal nisso: no mesmo fonte, tanto faz se pego do MySQL ou DBF.
Basta ir eliminando a necessidade do DBF e pronto, depois só apagar tudo do DBF.

Meu modo de trabalho

Enviado: 07 Mai 2020 12:00
por JoséQuintas
Só complementando:

Tá demorando pra terminar a conversão?
E daí?
Nenhum cliente pediu MySQL, está tudo ficando mais rápido e continua tudo funcionando.

Detalhe: antes o campo de número bancário era de 10 posições ou mais, por enquanto limitando a 6 posições, e depois (ou durante) trocar pra numérico no MySQL, e gravar StrZero(x,6) no DBF.
Melhor até alterar a pesquisa pelo número bancário pra já considerar numérico.
Esse é mais um motivo pra eu fazer devagar, porque estou ajustando campos.

E esse negócio de ter ID único numérico pra tudo que é arquivo/tabela é fantástico, simplifica muuuito, não importa se usa SQL ou DBF.

Em todo caso: no MySQL usando INT(11) significa que estou aumentando os limites pra BILHÕES de tudo que é tabela. Nunca mais me preocupar sobre estourar limites.

Meu modo de trabalho

Enviado: 11 Mai 2020 14:59
por JoséQuintas
Erro de hoje:
SYSTEM ERROR
Error BASE/1081 Argument error: +
Called from IMPRIME(395)
Called from PFINANRELPAGAR(101)
Called from DO(0)
Called from RUNMODULE(106)
Called from BOXMENU(753)
Called from BOXMENU(740)
Called from MENUPRINC(588)
Called from SISTEMA(87)
Called from (b)MAIN(58)
Tem a ver, ao mesmo tempo que não tem a ver com a migração SQL.

Código: Selecionar todos

               oPDF:DrawText( oPDF:nRow, 0, "***PORTADOR " + midPortador + ", " + Pad( AUXFINPORClass():Descricao( midPortador ), 30 ) + " ...:" )
Já comentei aqui: uma das mudanças que tenho feito é alterar campo chave de caractere pra numérico.

mIdPortador agora é numérico.

É por isso que eu disse que tem e não tem a ver... porque não é erro de migração SQL, e sim de mudança de estrutura pra aproveitar melhor recursos SQL.

É um erro DA MINHA MIGRAÇÃO, e não do MySQL... aliás, é uma variável.
E só acontece quando escolhe um determinado portador, na montagem de um sub-título que mostra opções selecionadas.

Dá pra considerar normal, porque aconteceria o mesmo com DBF. (apesar que no dbf continua como caractere, até sua extinção).

Meu modo de trabalho

Enviado: 11 Mai 2020 15:13
por JoséQuintas
A correção, apenas o uso de Str():

Código: Selecionar todos

oPDF:DrawText( oPDF:nRow, 0, "***PORTADOR " + Str( midPortador. 6 ) + ", " + Pad( AUXFINPORClass():Descricao( midPortador ), 30 ) + " ...:" )
O que leva a outra coisa: pra que continuar pesquisando o portador, se isso pode ser feito no próprio comando SQL?
Pois é... como eu já disse por aqui, é ir migrando devagar, e durante a migração vamos aprendendo e tirando cada vez mais proveito do SQL.

Usar SQLMIX é uma boa opção pra migração rápida, mas.... se até usando ADO diretamente essas coisas podem passar desapercebidas, imagem usando estilo DBF....

Convém destacar:

Isso NÃO tem a ver com escolher ADO pra conectar.
Isso está diretamente relacionado a tirar mais proveito do servidor MySQL e comandos SQL.
Talvez eu não tenha feito isso antes porque estava migrando uma tabela de cada vez, mas a partir da gravação dupla passou a ser possível tirar mais proveito de tudo, já que todas as tabelas ficaram disponíveis no MySQL.

E assim vai prosseguindo a minha conversão: devagar, até refazendo coisa que tinha feito antes, mas sempre em frente.

Meu modo de trabalho

Enviado: 11 Mai 2020 15:20
por JoséQuintas
JoséQuintas escreveu:mIdPortador agora é numérico.
Faltou acrescentar:
Durante a fase de migração, alterei essa função que trás a descrição pra aceitar tanto chave caractere como numérica.
Desta forma ela continuou valendo pra fontes novos e velhos.

Nada complicado, algo do tipo:

Código: Selecionar todos

FUNCTION Mostra( mIdPortador )

IF ValType( mIdPortador ) == "C"
   mIdPortador := Val( mIdPortador )
ENDIF
Desse jeito, tanto faz se ele é passado como caractere ou numérico, vale pro DBF que é caractere e pro MySQL que é numérico.
E quando terminar tudo, será remover esse IF (e outros que existirem).

Corrigindo: vale pra fonte novo e fonte velho, porque nos novos é sempre numérico, porque o foco principal é no tipo final.
No caso de DBF, leio como Val( arquivo->portador ) e gravo como StrZero( nIdPortador, 6 ), assim o aplicativo passa a trabalhar somente com numérico.
E quando remover o DBF, já remove a conversão junto.

Meu modo de trabalho

Enviado: 25 Mai 2020 13:16
por JoséQuintas
Vou começar a alterar esta parte agora.
É uma demonstração interessante de como "pensar em modo MySQL" é diferente de "pensar em modo DBF".

Código: Selecionar todos

METHOD UserFunction( lProcessou ) CLASS FinanEdReceberClass

   LOCAL oXmlPdf, nIdFinanceiro := ::axKeyValue[ 1 ]

   Encontra( StrZero( nIdFinanceiro, 6 ), "jpfinan", "numlan" )
   Encontra( jpfinan->fiCadastro, "jpcadastro", "numlan" )
   DO CASE
   CASE ::cOpc == "F3"
      ::GeraFatura()
   CASE ::cOpc == "O"
      PJPREGUSO( "JPFINAN", Val( jpfinan->idFinan ) )
   CASE ::cOpc == "W"
      IF Val( jpfinan->fiPedido ) != 0 .AND. ADORecCount( "JPNOTFIS", "NFPEDIDO = " + NumberSQL( jpfinan->fiPedido ) ) != 0
         PosicionaEmpresa( Val( jpfinan->nfFilial ) )
         oXmlPdf := XmlPdfClass():New()
         oXmlPdf:GetFromMySql( "", Val( jpfinan->fiNumDoc ), "55" )
         oXmlPdf:GeraPDF()
         PosicionaEmpresa()
      ELSE
         oXmlPdf := XmlPdfClass():New()
         oXmlPdf:GetFromMySql( "", Val( jpfinan->fiNumDoc ), "55", jpcadastro->cdCnpj )
         oXmlPdf:GeraPDF()
      ENDIF
   CASE ::cOpc == "Q"
      ::PesquisaDocto()
   CASE ::cOpc == "T"
      ::GuiHide()
      ::TrocaCheque()
      ::GuiShow()
   CASE ::cOpc == "B"
      ::BaixaDocto()
   OTHERWISE
      lProcessou := .F.
   ENDCASE

   RETURN lProcessou
Como já comentei por aqui, comecei eliminando um arquivo por vez, mas depois mudei de idéia no meio do caminho com a gravação dupla.
usa o JPFINAN - financeiro em DBF
pesquisa JPCADASTRO, em DBF, pra encontrar o cliente
pesquisa JPNOTFIS, em MYSQL, pra verificar se existe nota fiscal emitida

Usava o financeiro em DBF, posicionado em DBF, o registro atual.
Com base no ID ainda posiciono o DBF.

Dá pra perceber aí também que padronizei nIdFinanceiro, nIdFilial, nIdPedido, como numéricos, porque são campos chave, mesmo no DBF sendo caractere, porque no MySQL já são numéricos.

Meu modo de trabalho

Enviado: 25 Mai 2020 13:24
por JoséQuintas
Fazer em duas etapas pra facilitar, apesar que é pequeno e nem precisava.
Substitui o acesso aos campos por variáveis, porque isso virá do MySQL.

Código: Selecionar todos

METHOD UserFunction( lProcessou ) CLASS FinanEdReceberClass

   LOCAL oXmlPdf, nIdFinanceiro, nIdPedido, nIdFilial, nNumDoc, cCnpj

   nIdFinanceiro := ::axKeyValue[ 1 ]

   Encontra( StrZero( nIdFinanceiro, 6 ), "jpfinan", "numlan" )
   Encontra( jpfinan->fiCadastro, "jpcadastro", "numlan" )
   nIdPedido := Val( jpfinan->fiPedido )
   nIdFilial := Val( jpfinan->nfFilial )
   nNumDoc   := Val( jpfinan->fiNumDoc )
   cCnpj     := jpcadastro->cdCnpj

   DO CASE
   CASE ::cOpc == "F3"
      ::GeraFatura()
   CASE ::cOpc == "O"
      PJPREGUSO( "JPFINAN", nIdFinanceiro )
   CASE ::cOpc == "W"
      IF Val( jpfinan->fiPedido ) != 0 .AND. ADORecCount( "JPNOTFIS", "NFPEDIDO = " + NumberSQL( nIdPedido ) ) != 0
         PosicionaEmpresa( nIdFilial )
         oXmlPdf := XmlPdfClass():New()
         oXmlPdf:GetFromMySql( "", nNumDoc, "55" )
         oXmlPdf:GeraPDF()
         PosicionaEmpresa()
      ELSE
         oXmlPdf := XmlPdfClass():New()
         oXmlPdf:GetFromMySql( "", nNumDoc, "55", cCnpj )
         oXmlPdf:GeraPDF()
      ENDIF
   CASE ::cOpc == "Q"
      ::PesquisaDocto()
   CASE ::cOpc == "T"
      ::GuiHide()
      ::TrocaCheque()
      ::GuiShow()
   CASE ::cOpc == "B"
      ::BaixaDocto()
   OTHERWISE
      lProcessou := .F.
   ENDCASE

   RETURN lProcessou
Agora é substituir a origem das variáveis para o MySQL.

Meu modo de trabalho

Enviado: 25 Mai 2020 13:31
por JoséQuintas
Pronto.
Um único comando resolveu tudo, até a parte de fonte anterior de MySQL.

Código: Selecionar todos

METHOD UserFunction( lProcessou ) CLASS FinanEdReceberClass

   LOCAL oXmlPdf, nIdFinanceiro, nIdPedido, nIdFilial, nNumDoc, cCnpj
   LOCAL cnSQL := ADOClass():New( AppConexao() )

   nIdFinanceiro := ::axKeyValue[ 1 ]
   WITH OBJECT cnSQL
      :cSQL := "SELECT FIPEDIDO, NFFILIAL, FINUMDOC, FICADASTRO," + ;
         " JPNOTFIS.IDNOTFIS, JPNOTFIS.NFFILIAL, " + ;
         " JPCADASTRO.CDCNPJ " + ;
         " FROM JPFINAN " + ;
         " LEFT JOIN JPPEDIDO ON JPPEDIDO.IDPEDIDO = JPFINAN.FIPEDIDO" + ;
         " LEFT JOIN JPNOTFIS ON JPNOTFIS.NFPEDIDO = JPPEDIDO.IDPEDIDO" + ;
         " WHERE IDFINAN = " + NumberSQL( nIdFinanceiro )
      :Execute()
      nIdPedido := :Number( "FIPEDIDO" )
      nIdFilial := :Number( "NFFILIAL" )
      nNumDoc   := :Number( "FINUMDOC" )
      cCnpj     := :String( "CDCNPJ" )
      :CloseRecordset()
   ENDWITH

   DO CASE
   CASE ::cOpc == "F3"
      ::GeraFatura()
   CASE ::cOpc == "O"
      PJPREGUSO( "JPFINAN", nIdFinanceiro )
   CASE ::cOpc == "W"
      IF nIdPedido != 0 .AND. nIdFilial != 0
         PosicionaEmpresa( nIdFilial )
         oXmlPdf := XmlPdfClass():New()
         oXmlPdf:GetFromMySql( "", nNumDoc, "55" )
         oXmlPdf:GeraPDF()
         PosicionaEmpresa()
      ELSE
         oXmlPdf := XmlPdfClass():New()
         oXmlPdf:GetFromMySql( "", nNumDoc, "55", cCnpj )
         oXmlPdf:GeraPDF()
      ENDIF
   CASE ::cOpc == "Q"
      ::PesquisaDocto()
   CASE ::cOpc == "T"
      ::GuiHide()
      ::TrocaCheque()
      ::GuiShow()
   CASE ::cOpc == "B"
      ::BaixaDocto()
   OTHERWISE
      lProcessou := .F.
   ENDCASE

   RETURN lProcessou
Nota: já conferi as outras sub-rotinas chamadas, e não dependem mais do posicionamento do DBF.

Este trecho é interessante pelo seguinte:
Mostra que pode ser mais interessante mover vários arquivos de uma vez, ao invés de um por um.
E é justamente aí que a gravação dupla foi vantagem: ao invés de alterar o fonte pra um arquivo MySQL por vez, já altero o fonte em definitivo.

Por enquanto fica assim, depois se aprender algo mais prático, ou redesenhar as bases de dados, faço de outro jeito.
Isso também mostra porque já padronizei os fontes pra usar campos numéricos, diferentes do DBF, porque já estão usando o formato final do MySQL.

E mais uma "não visível":

NÃO precisa de arquivo aberto, ou arquivo posicionado, bastam as variáveis contendo a informação.
Se o usuário largar o aplicativo aberto.... trata-se somente do aplicativo aberto, e uma única conexão pra troca de mensagens com MySQL, e nada mais.

Se fosse DBF: arquivos abertos, índices abertos, no terminal e no servidor, mais tempo do Windows pra manter tudo conectado, etc. etc. etc.

Como eu já disse por aqui: pensar "igual SQL", e esquecer como o DBF funciona. Não ter o DBF aberto e posicionado e trazer tudo pronto são as principais diferenças.
E não foi usado disco pra nada, apenas troca de mensagens entre aplicativo e servidor.