Clipper On Line • Ver Tópico - Meu modo de trabalho

Meu modo de trabalho

Aqui você poderá oferecer suas Contribuições, Dicas e Tutoriais (Texto ou Vídeo) que sejam de interesse de todos.

Moderador: Moderadores

 

Meu modo de trabalho

Mensagempor JoséQuintas » 19 Jul 2020 17:43

Cabe um comentário interessante sobre o fonte:

No geral, as modificações foram para organizar o fonte, e não para o SQL.
Os 3 módulos que pegariam do DBF, agora pegam do SQL, e até que ficaram relativamente simples.

Antes, acabava gravando no DBF, só por causa da visualização.
A gravação foi eliminada com o uso de array.
O resto passou a ser só consulta, que é o que deveria ser desde o começo.

Também poderia ser um recordset ADO local, ao invés de array.... mas assim tá bom.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18013
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

Meu modo de trabalho

Mensagempor JoséQuintas » 19 Jul 2020 17:55

Este outro eu até já sei o que vou usar.
Este altera toda ordem do bancário, pra mostrar tudo junto e misturado, não importa a conta.
Outra gravação no DBF que não deveria existir.

Usando o resultado de outras pesquisas pela internet, vai ser substituído por um único comando SQL.

/*
PBANCOCONSOLIDA - SALDO CONSOLIDADO DAS CONTAS
1994.04 José Quintas
*/

#include "inkey.ch"

MEMVAR mRecalcAuto, m_Filtro

PROCEDURE pBancoConsolida

   LOCAL mDataIni, m_Saldo, m_DtBco, m_DtEmi, oTBrowse
   LOCAL cnSQL := ADOClass():New( AppConexao() )

   m_FIltro := {} // pra usar na funcao chamada
   mRecalcAuto := .T. // necessaria ref. recalculo
   mDataIni := Ctod("") // para uso da funcao pBancoLanca
   HB_SYMBOL_UNUSED( mRecalcAuto + mDataIni )
   IF ! AbreArquivos( "jpempresa", "jptabel", "jpconfi", "jpbaccusto", "jpbancario" )
      RETURN
   ENDIF
   WITH OBJECT cnSQL
      SELECT jpbaccusto
      GOTO TOP
      SELECT jpbancario

      Mensagem( "Aguarde... Efetuando cálculos..." )
      SELECT jpbancario
      OrdSetFocus( "bancario3" )
      GOTO TOP
      m_Saldo = 0
      DO WHILE ! Eof()
         Grafproc()
         m_saldo += jpbancario->bavalor
         :QueryCreate()
         :QueryAdd( "BASALDO", m_Saldo )
         jpbancario->( :DBFQueryExecuteUpdate( "JPBANCARIO" ) )
         :QueryExecuteUpdate( "JPBANCARIO", "IDBANCARIO = " + NumberSQL( jpbancario->idBancario ) )
         SKIP
      ENDDO
      GOTO BOTTOM
      m_dtbco = Ctod("")
      m_dtemi = Ctod("")
      DO WHILE ! Bof()
         GrafProc()
         IF jpbancario->baDatBan != m_dtbco
            IF jpbancario->baImpSld != "S"
               :QueryCreate()
               :QueryAdd( "BAIMPSLD", "S" )
               jpbancario->( :DBFQueryExecuteUpdate( "JPBANCARIO" ) )
               :QueryExecuteUpdate( "JPBANCARIO", "IDBANCARIO = " + NumberSQL( jpbancario->idBancario ) )
            ENDIF
         ELSEIF jpbancario->baDatBan == Stod( "29991231" ) .AND. jpbancario->baDatEmi != m_dtemi
            IF jpbancario->baImpSld != "S"
               :QueryCreate()
               :QueryAdd( "BAIMPSLD", "S" )
               jpbancario->( :DBFQueryExecuteUpdate( "JPBANCARIO" ) )
               :QueryExecuteUpdate( "JPBANCARIO", "IDBANCARIO = " + NumberSQL( jpbancario->idBancario ) )
            ENDIF
         ELSEIF jpbancario->baImpSld == "S"
            :QueryCreate()
            :QueryAdd( "BAIMPSLD", "N" )
            jpbancario->( :DBFQueryExecuteUpdate( "JPBANCARIO" ) )
            :QueryExecuteUpdate( "JPBANCARIO", "IDBANCARIO = " + NumberSQL( jpbancario->idBancario ) )
         ENDIF
         m_dtbco = jpbancario->baDatBan
         m_dtemi = jpbancario->baDatEmi
         SKIP -1
      ENDDO
      SEEK Dtos( Date() ) SOFTSEEK
      Mensagem( "I Inclui, A Altera, E Exclui, Ctrl-L Pesquisa, ESC Sai" )
      oTBrowse := { ;
         { "BANCO",         { || iif( jpbancario->baValor == 0, Replicate( "-", 8 ), iif( jpbancario->baDatBan == Stod( "29991231" ), Space(8), Dtoc( jpbancario->baDatBan ) ) ) } }, ;
         { "EMISSÃO",       { || iif( jpbancario->baValor == 0, Replicate( "-", 8 ), iif( jpbancario->baDatEmi == Stod( "29991231" ), Space(8), Dtoc( jpbancario->baDatEmi ) ) ) } }, ;
         { "DESP/REC",      { || iif( jpbancario->baValor == 0, Replicate( "-", Len( jpbancario->baResumo ) ), jpbancario->baResumo ) } }, ;
         { "HISTÓRICO",     { || iif( jpbancario->baValor == 0, Pad( jpbancario->baConta + iif( jpbancario->baAplic == "S", "(Aplicação)", "" ), Len( jpbancario->bahist ) ), jpbancario->baHist ) } }, ;
         { "ENTRADA",       { || iif( jpbancario->baValor > 0, Transform( Abs( jpbancario->baValor ), PicVal(14,2) ), Space( Len( Transform( 0, PicVal(14,2) ) ) ) ) } }, ;
         { "SAÍDA",         { || iif( jpbancario->baValor < 0, Transform( Abs( jpbancario->baValor ), PicVal(14,2) ), Space( Len( Transform( 0, PicVal(14,2) ) ) ) ) } }, ;
         { "SALDO",         { || iif( jpbancario->baImpSld == "S", Transform( jpbancario->baSaldo, PicVal(14,2) ), Space( Len( Transform( jpbancario->baSaldo, PicVal(14,2) ) ) ) ) } }, ;
         { " ",             { || ReturnValue( " ", vSay( 2, 0, "CONTA " + jpbancario->baConta ) ) } } }
      DO WHILE .T.
         BrowseDbfRC( 4, 0, MaxRow() - 3, MaxCol(), oTBrowse, { | b, k | DigBancoLanca( b, k ) } )
         IF LastKey() == K_ESC
            EXIT
         ENDIF
      ENDDO
      OrdSetFocus( "bancario1" )
   ENDWITH
   RecalculoBancario()
   CLOSE DATABASES

   RETURN
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18013
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

Meu modo de trabalho

Mensagempor JoséQuintas » 19 Jul 2020 18:27

Pronto, com duas coisas novas, pra mim, do MySQL:

#include "inkey.ch"

PROCEDURE pBancoConsolida

   LOCAL oTBrowse
   LOCAL cnSQL := ADOClass():New( AppConexao() )

   WITH OBJECT cnSQL
      :cSQL := "SET @SOMA = 0"
      :ExecuteCmd()
      :cSQL := "SELECT BADATBAN, BADATEMI, BARESUMO, BAHIST, " + ;
         " IF( BAVALOR > 0, BAVALOR, 0 ) AS ENTRADA," + ;
         " IF( BAVALOR < 0, BAVALOR, 0 ) AS SAIDA," + ;
         " @SOMA := @SOMA + BAVALOR AS SALDO" + ;
         " FROM JPBANCARIO" + ;
         " WHERE BAVALOR <> 0"  + ;
         " ORDER BY BADATBAN, BADATEMI, IDBANCARIO"
      :Execute()
      oTBrowse := { ;
         { "BANCO",     { || if( :Date( "BADATBAN" ) = Stod( "29991231" ), Space(8), Dtoc( :Date( "BADATBAN" ) ) ) } }, ;
         { "EMISSAO",   { || :Date( "BADATEMI" ) } }, ;
         { "CCUSTO",    { || :String( "BARESUMO", 10 ) } }, ;
         { "HISTORICO", { || :String( "BAHIST", 50 ) } }, ;
         { "ENTRADAS",  { || Transform( :Number( "ENTRADA" ), "@ZE 999,999,999.99" ) } }, ;
         { "SAIDAS",    { || Transform( :Number( "SAIDA" ), "@ZE 999,999,999.99" ) } }, ;
         { "SALDO",     { || Transform( :Number( "SALDO" ), "@E 999,999,999.99" ) } } }
      BrowseADO( cnSQL, oTBrowse, "BAHIST", { || "" } )
      :cSQL := "SET @SOMA = NULL"
      :ExecuteCmd()
      :CloseRecordset()
   ENDWITH
   KEYBOARD ""
   CLOSE DATABASES

   RETURN


De novidade, criar uma variável no início e apagar no final.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18013
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

Meu modo de trabalho

Mensagempor JoséQuintas » 20 Jul 2020 14:12

Tem uma coisa que tive que retirar no browse anterior.... mas acho que tem solução.

Mostrar o saldo apenas no último lançamento do dia.

Vai ser um comando "diferente", mas acho que dá.
Um comando parecido, uma coluna S/N, mudou a data, altera pra S
O detalhe é que isso precisa ser em ordem decrescente de data, e o browse precisa em ordem crescente.

Pensei numa possibilidade, que parece maluca, mas é relativamente simples:

SELECT ..... ORDER BY ASC // este aqui só altera ordem
FROM
( SELECT ... ORDER BY DESC ) // este aqui altera mostrar s/n
FROM
( SELECT ... ORDER BY ASC ) // este aqui calcula saldo


Pego em ordem crescente pra fazer a conta do saldo
Depois em decrescente, pra colocar esse Sim ou Não quando alterar data
Depois novamente em crescente pra ficar na ordem da tela

Pra otimizar, e usar menos memória do servidor, TALVEZ fazer os selects só da parte que interessa, e no final relacionar e trazer o histórico.
TALVEZ, sei lá se isso ajuda ou atrapalha o servidor.

Talvez esteja na hora de usar alguma ferramenta que analise os processos do servidor.
Nenhum problema até agora, mas.... como eu digo sempre, melhor ver isso quando está tudo tranquilo, do que quando estiver com problema.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18013
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

Meu modo de trabalho

Mensagempor Vlademiro » 20 Jul 2020 21:38

Você poderia criar views para as consultas mais complexas, aí não precisaria escrever sempre selects mais complexos no seu código. Só precisa de um sistema de trabalho para gravar essas views (uma espécie de dicionário). As view não poupam recursos, porque o select continua sendo o mesmo, mas facilita para você.
Avatar de usuário

Vlademiro
Usuário Nível 4

Usuário Nível 4
 
Mensagens: 749
Data de registro: 11 Jul 2005 02:46
Curtiu: 22 vezes
Mens.Curtidas: 62 vezes

Meu modo de trabalho

Mensagempor JoséQuintas » 20 Jul 2020 22:41

Vlademiro escreveu:Você poderia criar views para as consultas mais complexas


Por enquanto ainda evitando isso, até porque ainda não me senti seguro com o backup do MySQL contendo VIEW.
Achei que no backup o view fica esquisito, diferente do comando usado pra criação.
Tô mais pra gravar o comando numa tabela normal do que num view.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18013
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

Meu modo de trabalho

Mensagempor Vlademiro » 20 Jul 2020 23:16

Pense na view como uma espécie de variável. O backup de uma view é só o seu comando de criação Create view ... Ela faz parte da estrutura do banco, não dos dados.
Avatar de usuário

Vlademiro
Usuário Nível 4

Usuário Nível 4
 
Mensagens: 749
Data de registro: 11 Jul 2005 02:46
Curtiu: 22 vezes
Mens.Curtidas: 62 vezes

Meu modo de trabalho

Mensagempor Vlademiro » 20 Jul 2020 23:25

O único problema grave que um banco de dados pode apresentar, na minha opinião, é ele ficar lento devido a triggers e store procedures que vc cria. A gente vai se empolgando e começa a passar toda a lógica de negócios para o banco. Se isso não for bem feito, o banco fica lento. Os especialistas, não eu, recomendam não abusar desse recurso. Quanto a view ela é uma forma de tornar o comando select mais fácil para vc manter no futuro. Se vc mecher em alguma tabela, mudar o nome dos campos, a view correspondente vai parar de funcionar. Outro cuidado é não criar selects muito complexos para não deixar o banco lento. As vezes se for um relatório de fim de mês compensa, mas para uso diário não. Para isso existem ferramentas que analisam o desempenho do select ente ajudam a encontrar bgargalos.
Avatar de usuário

Vlademiro
Usuário Nível 4

Usuário Nível 4
 
Mensagens: 749
Data de registro: 11 Jul 2005 02:46
Curtiu: 22 vezes
Mens.Curtidas: 62 vezes

Meu modo de trabalho

Mensagempor Vlademiro » 20 Jul 2020 23:36

Já trabalhei com MySQL há uns 15 anos. Era um sistema que ficava na web recebendo dados de rastreadores que eram alugados. Cada rastreador mandava dados para o banco a cada minuto. Quando o carro parava o rastreador mandava a cada 30 minutos. Em uma semana o banco MySql tinha 40 milhões de registros. Como a estrutura de servidor e disco era modesta, a gente migrava o resumo para um outro banco a cada mês. MySQL é um ótimo banco, vc não deveria ter receio das views. Kkkkk
Avatar de usuário

Vlademiro
Usuário Nível 4

Usuário Nível 4
 
Mensagens: 749
Data de registro: 11 Jul 2005 02:46
Curtiu: 22 vezes
Mens.Curtidas: 62 vezes

Meu modo de trabalho

Mensagempor Vlademiro » 20 Jul 2020 23:38

E olha que meu ex chefe, já de saudosa memória, era meio doido. O primeiro servidor era um windows xp . Só depois descobrimos que o xp recusava conexões TCP depois de um certo limite. A gente tava botando a culpa no MySQL mas era windows. Depois disso ele colocou um windows server.
Avatar de usuário

Vlademiro
Usuário Nível 4

Usuário Nível 4
 
Mensagens: 749
Data de registro: 11 Jul 2005 02:46
Curtiu: 22 vezes
Mens.Curtidas: 62 vezes

Meu modo de trabalho

Mensagempor JoséQuintas » 21 Jul 2020 00:11

Vlademiro escreveu:Só depois descobrimos que o xp recusava conexões TCP depois de um certo limite


Antes do XP não havia limites. No XP há o limite de "half-open connections" de apenas 8.
Acima disso, começa a ser criada uma fila, que pode até travar tudo se ficar longa.
São conexões em andamento, abrindo e/ou fechando.
Segundo a Microsoft foi pra segurança, pra controlar melhor conexões porque usam sobrecarga pra invasão.

Já vi que conforme o VIEW, ele faz um SELECT COMPLETO, e não parcial, então também precisa tomar cuidado com ele.

Confundi, não é o VIEW que fica diferente no backup, é a STORED PROCEDURE.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18013
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

Meu modo de trabalho

Mensagempor JoséQuintas » 21 Jul 2020 21:58

maiores DBFs ainda existentes, no cliente referência:

06/07/2020  11:25           314.624 jpsenha.dbf
03/03/2020  02:33         1.254.539 jpcidade.dbf
21/07/2020  16:07        16.368.631 jpbancario.dbf
              16 arquivo(s)     18.397.775 bytes


o bancário representa quase que o total dos DBFs.
E o último único fonte que precisa do DBF, ainda em andamento.

/*
PBANCOLANCA - MOVIMENTACAO BANCARIA
1989.09 José Quintas

2018.05.21 Opção de excluir tudo de uma conta
*/

#include "tbrowse.ch"
#include "inkey.ch"

MEMVAR m_Prog
MEMVAR m_Filtro, dDataInicial
MEMVAR m_Alterou
MEMVAR mbaConta, m_Aplic, m_Confirma

PROCEDURE pBancoLanca

   LOCAL GetList := {}, oTbrowse, cTempFile, oElement
   LOCAL oFrm := frmGuiClass():New()
   LOCAL cnSQL := ADOClass():New( AppConexao() )

   IF ! AbreArquivos( "jpempresa", "jptabel", "jpconfi", "jpbancario" )
      RETURN
   ENDIF
   SELECT jpbancario

   dDataInicial := Date() - 20
   @ 12, 3 SAY "Data inicial: " GET dDataInicial
   Mensagem( "Digite data inicial a visualizar, ESC sai" )
   READ
   Mensagem()

   IF LastKey() == K_ESC
      CLOSE DATABASES
      RETURN
   ENDIF
   oFrm:cOptions := "IAE"
   oFrm:lNavigate := .F.
   AAdd( oFrm:acMenuOptions, "<F>Filtro" )
   AAdd( oFrm:acMenuOptions, "<Ctrl-L>Pesquisa" )
   AAdd( oFrm:acMenuOptions, "<R>Recalc." )
   AAdd( oFrm:acMenuOptions, "<S>SomaL" )
   AAdd( oFrm:acMenuOptions, "<P>Aplic" )
   AAdd( oFrm:acMenuOptions, "<C>Conta" )
   AAdd( oFrm:acMenuOptions, "<N>N.Conta" )
   AAdd( oFrm:acMenuOptions, "<F4>Exc.Conta" )
   AAdd( oFrm:acMenuOptions, "<T>T.Conta" )
   oFrm:FormBegin()

   IF IsMaquinaJPA()
      WITH OBJECT cnSQL
         :cSQL := "SELECT BACONTA, BAAPLIC, BADATBAN, BADATEMI, BAHIST, BAVALOR," + ;
            " IDBANCARIO, BASALDO, BARESUMO, BAIMPSLD, IF( BAVALOR < 0, 2, 1 ) AS ORDEM" + ;
            " FROM JPBANCARIO" + ;
            " WHERE BADATBAN >= CAST( " + DateSQL( dDataInicial - 1 ) + " AS DATE )" + ;
            " OR BAVALOR = 0" + ;
            " ORDER BY BACONTA, BAAPLIC, BADATBAN, BADATEMI, ORDEM, IDBANCARIO"
         oTBrowse := { ;
            { "BANCO",     { || iif( :Number( "BAVALOR" ) == 0, Space(8), ;
            iif( :Date( "BADATBAN" ) == Stod( "29991231" ), Space(8), :Date( "BADATBAN" ) ) ) } }, ;
            { "EMISSAO",   { || iif( :Number( "BAVALOR" ) == 0, Space(8), :Date( "BADATEMI" ) ) } }, ;
            { "CCUSTO",    { || iif( :Number( "BAVALOR" ) == 0, Space(10), :String( "BARESUMO", 10 ) ) } }, ;
            { "HISTORICO", { || iif( :Number( "BAVALOR" ) == 0, ;
                                Padc( :String( "BACONTA" ) + iif( :String( "BAAPLIC" ) == "S", "(Aplicacao)", "" ), 45 ), ;
                                :String( "BAHIST", 45 ) ) } }, ;
            { "ENTRADA",   { || iif( :Number( "BAVALOR" ) > 0, Transform( Abs( :Number( "BAVALOR" ) ), PicVal(14,2) ), ;
                                Space( Len( Transform( 0, PicVal(14,2) ) ) ) ) } }, ;
            { "SAIDA",     { || iif( :Number( "BAVALOR" ) < 0, Transform( Abs( :Number( "BAVALOR" ) ), PicVal(14,2) ), ;
                                Space( Len( Transform( 0, PicVal(14,2) ) ) ) ) } }, ;
            { "SALDO",     { || iif( :String( "BAIMPSLD" ) == "S", ;
                                Transform( :Number( "BASALDO" ), PicVal(14,2) ), ;
                                Space( Len( Transform( 0, PicVal(14,2) ) ) ) ) } } }
         FOR EACH oElement IN oTbrowse
            AAdd( oElement, { || iif( :Number( "BAVALOR" ) == 0, { 5, 2 }, { 1, 2 } ) } )
         NEXT
         :Execute()
         BrowseADORC( 7, 0, MaxRow() - 3, MaxCol(), cnSQL, oTBrowse, "BACONTA,BARESUMO,BAHIST", { || "" }, { || EditLanc( cnSQL ) } )
         KEYBOARD ""
      ENDWITH
   ENDIF

   SELECT jpbancario
   cTempFile := MyTempFile( "CDX" )
   INDEX ON jpbancario->baConta + jpbancario->baAplic + Dtos( jpbancario->baDatBan ) + Dtos( jpbancario->baDatEmi ) + ;
      iif( jpbancario->baValor > 0, "1", "2" ) + StrZero( jpbancario->( RecNo() ), 6 ) TAG TEMP TO ( cTempFile ) ;
      FOR Dtos( jpbancario->baDatBan ) >= Dtos( dDataInicial ) .OR. ( jpbancario->baValor == 0 )
   SET INDEX TO ( PathAndFile( "jpbancario" ) ), ( cTempFile )
   OrdSetFocus( "temp" )

   m_Filtro := {}
   SET FILTER TO Filtro()
   SEEK jpbancario->baConta + jpbancario->baAplic + Dtos( Date() ) SOFTSEEK
   SKIP -1

   oTBrowse := { ;
      { "BANCO",     { || iif( jpbancario->baValor == 0, Space(8), ;
                          iif( jpbancario->baDatBan == Stod( "29991231" ), Space(8), ;
                          Dtoc( jpbancario->baDatBan ) ) ) } }, ;
      { "EMISSÃO",   { || iif( jpbancario->baValor == 0, Space(8), ;
                          iif( jpbancario->baDatEmi == Stod( "29991231" ), Space(8), ;
                          Dtoc( jpbancario->baDatEmi ) ) ) } }, ;
      { "CCUSTO",    { || iif( jpbancario->baValor == 0, Space( Len( jpbancario->baResumo ) ), ;
                          jpbancario->baResumo ) } }, ;
      { "HISTÓRICO", { || iif( jpbancario->baValor == 0, Padc( jpbancario->baConta + iif( jpbancario->baAplic == "S", "(Aplicação)", "" ), Len( jpbancario->bahist ) ), ;
                          jpbancario->baHist ) } }, ;
      { "ENTRADA",   { || iif( jpbancario->baValor > 0, Transform( Abs( jpbancario->baValor ), PicVal(14,2) ), ;
                          Space( Len( Transform( 0, PicVal(14,2) ) ) ) ) } }, ;
      { "SAÍDA",     { || iif( jpbancario->baValor < 0, Transform( Abs( jpbancario->baValor ), PicVal(14,2) ), ;
                          Space( Len( Transform( 0, PicVal(14,2) ) ) ) ) } }, ;
      { "SALDO",     { || iif( jpbancario->baImpSld == "S", Transform( jpbancario->baSaldo, PicVal(14,2) ), ;
                          Space( Len( Transform( jpbancario->baSaldo, PicVal(14,2) ) ) ) ) } } }
   FOR EACH oElement IN oTbrowse
      AAdd( oElement, { || iif( jpbancario->baValor == 0, { 5, 2 }, { 1, 2 } ) } )
   NEXT
   DO WHILE .T.
      Cls()
      Mensagem( "I Inclui, A Altera, E Exclui, C-L Pesquisa, P Aplicação, C Contas, " + ;
         "N Nova_conta, F Filtro,  R Recálculo, T Troca_conta, S Soma_Lançtos, " + ;
         "D Desliga_Recálculo, F4 Exclui_Conta, ESC sai" )
      KEYBOARD Chr( 205 )
      Inkey(0)
      BrowseDbfRC( 7, 0, MaxRow() - 3, MaxCol(), oTBrowse, { | b, k, cnSQL | DigBancoLanca( b, k, cnSQL ) } )
      Mensagem()
      IF LastKey() == K_ESC
         EXIT
      ENDIF
   ENDDO
   CLOSE DATABASES
   oFrm:FormEnd()
   fErase( cTempFile )

   RETURN

FUNCTION EditLanc( b, k, cnSQL )

   (b)
   (k)
   (cnSQL)

   RETURN TBR_CONTINUE

FUNCTION DigBancoLanca( ... ) // NAO STATIC usada em pBancoConsolida

   LOCAL nRecNo, m_Aplic, mbaConta

   IF LastKey() == K_ESC
      RETURN 0
   ENDIF
   m_Alterou = .F.
   DO CASE
   CASE Chr( LastKey() ) $ "Ss" .AND. m_Prog == "PBANCOLANCA"
      SomaFiltro()

   CASE Chr( LastKey() ) $ "Tt" .AND. m_Prog == "PBANCOLANCA"
      TrocaConta()

   CASE Chr( LastKey() ) $ "Rr"
      nRecNo := RecNo()
      BARecalcula()
      GOTO ( nRecNo )

   CASE Chr( LastKey() ) $ "Nn" .AND. m_Prog == "PBANCOLANCA"
      NovaConta()

   CASE Chr( LastKey() ) $ "Pp" .AND. m_Prog == "PBANCOLANCA"
      mbaConta = jpbancario->baConta
      m_Aplic = iif( jpbancario->baAplic == "S", "N", "S" )
      ve_Conta( mbaConta, m_Aplic )

   CASE Chr( LastKey() ) $ "Ff"
      DO DigFiltro

   CASE Chr( LastKey() ) $ "Cc" .AND. m_Prog == "PBANCOLANCA"
      DO DigConta

   CASE LastKey() == K_CTRL_L .AND. m_Prog == "PBANCOLANCA"
      pBancoLancaLocaliza()
      RETURN TBR_EXIT

   CASE Chr( LastKey() ) == "2"
      KEYBOARD Chr( K_DOWN )
      RETURN TBR_CONTINUE

   CASE Chr( LastKey() ) == "8"
      KEYBOARD Chr( K_UP )
      RETURN TBR_CONTINUE

   CASE LastKey() == K_HOME .OR. Chr( LastKey() ) == "7"
      KEYBOARD Chr( K_CTRL_PGUP )
      RETURN TBR_CONTINUE

   CASE LastKey() == K_CTRL_PGDN .OR. Chr( LastKey() ) == "1"
      KEYBOARD Chr( K_CTRL_PGDN )
      RETURN TBR_CONTINUE

   CASE LastKey() == K_INS .OR. Chr( LastKey() ) == "0" .OR. Chr( LastKey() ) $ "Ii"
      cadlanc( "INCLUSAO" )
      RETURN TBR_CONTINUE

   CASE LastKey() == K_DEL .OR. Chr( LastKey() ) == "." .OR. Chr( LastKey() ) $ "Ee"
      cadlanc( "EXCLUSAO" )
      RETURN TBR_CONTINUE

   CASE LastKey() == K_ENTER .OR. Chr( LastKey() ) $ "Aa"
      IF jpbancario->baValor != 0
         nRecNo := RecNo()
         cadlanc( "ALTERACAO" )
         IF nRecNo != RecNo() .OR. m_Alterou .OR. ! Filtro()
            RETURN TBR_EXIT
         ENDIF
      ENDIF
      RETURN TBR_CONTINUE

   CASE LastKey() == K_F4
      ExcluiConta()
      RETURN TBR_EXIT

   ENDCASE

   RETURN TBR_CONTINUE

STATIC PROCEDURE TrocaConta

   LOCAL GetList := {}, mbaConta, nRecNo, mbaContaOld
   LOCAL cnSQL := ADOClass():New( AppConexao() )

   mbaConta    := jpbancario->baConta
   mbaContaOld := mbaConta
   WOpen( 5, 5, 9, 75, "Troca para Conta" )
   nRecNo := RecNo()
   @ 7, 15 SAY "Conta..:" GET mbaConta PICTURE "@!" VALID ValidBancarioConta( @mbaConta )
   Mensagem( "Digite Conta, F9 pesquisa, ESC Sai" )
   READ
   Mensagem()
   GOTO ( nRecNo )
   IF jpbancario->baConta != mbaConta .AND. LastKey() != K_ESC
      IF MsgYesNo( "Confirme transferência para esta Conta?" )
         WITH OBJECT cnSQL
            :QueryCreate()
            :QueryAdd( "BACONTA", mbaConta )
            jpbancario->( :DBFQueryExecuteUpdate( "JPBANCARIO" ) )
            :QueryExecuteUpdate( "JPBANCARIO", "IDBANCARIO = " + NumberSQL( jpbancario->idBancario ) )
         ENDWITH
         nRecNo := RecNo()
         BARecalcula( mbaConta )
         BARecalcula( mbaContaOld )
         GOTO ( nRecNo )
      ENDIF
   ENDIF
   WClose()

   RETURN

STATIC FUNCTION Filtro()

   LOCAL oElement, mReturn

   mReturn := .T.
   IF jpbancario->baValor != 0
      FOR EACH oElement IN m_Filtro
         DO CASE
         CASE oElement $ jpbancario->baResumo
         CASE oElement $ jpbancario->baHist
         CASE oElement $ Dtoc( jpbancario->baDatEmi )
         CASE oElement $ Dtoc( jpbancario->baDatBan )
         CASE oElement $ jpbancario->baConta
         CASE Val( oElement ) != 0 .AND. Val( oElement ) == Abs( jpbancario->baValor )
         OTHERWISE
            mReturn := .F.
            EXIT
         ENDCASE
      NEXT
      IF Type( "dDataInicial" ) == "D"
         IF Dtos( dDataInicial ) > Dtos( jpbancario->baDatBan )
            mReturn := .F.
         ENDIF
      ENDIF
   ENDIF
   GrafProc()

   RETURN mReturn

STATIC FUNCTION ExcluiConta()

   LOCAL cConta := jpbancario->baConta, cConfirma := "NAO", GetList := {}, cOrdSetFocus

   Mensagem( "Confirme se vai excluir tudo sobre a conta " + cConta + " digitando SIM" )
   @ Row(), Col() + 2 GET cConfirma PICTURE "@!A"
   READ
   IF LastKey() == K_ESC .OR. cConfirma != "SIM"
      RETURN NIL
   ENDIF
   SELECT jpbancario
   cOrdSetFocus := OrdSetFocus()
   OrdSetFocus( "bancario1" )
   DO WHILE .T.
      SEEK cConta
      IF Eof()
         EXIT
      ENDIF
      RecLock()
      DELETE
      RecUnlock()
   ENDDO
   OrdSetFocus( cOrdSetFocus )

   RETURN NIL

STATIC FUNCTION NovaConta()

   LOCAL cTxt := Space(15), GetList := {}, nIdBancario
   LOCAL cnSQL := ADOClass():New( AppConexao() )

   Mensagem( "Digite nova Conta, ESC Sai" )
   @ Row(), Col() + 2 GET cTxt PICTURE "@!"
   READ
   Mensagem()
   IF LastKey() != K_ESC
      WITH OBJECT cnSQL
         :QueryCreate()
         :QueryAdd( "BACONTA", cTxt )
         :QueryAdd( "BAAPLIC", "N" )
         nIdBancario := :QueryExecuteInsert( "JPBANCARIO" )
         :QueryAdd( "IDBANCARIO", StrZero( nIdBancario, 6 ) )
         jpbancario->( :DBFQueryExecuteInsert( "JPBANCARIO" ) )
      ENDWITH
   ENDIF

   RETURN NIL

STATIC FUNCTION ve_Conta

   LOCAL m_RecNo, nIdBancario
   LOCAL cnSQL := ADOClass():New( AppConexao() )

   PARAMETERS mbaConta, m_Aplic, m_Confirma

   IF pcount() < 3
      PRIVATE m_Confirma

      m_Confirma := .T.
   ENDIF
   m_RecNo := RecNo()
   SEEK mbaConta + m_Aplic
   IF Eof()
      IF m_Confirma
         IF ! MsgYesNo( "Conta e/ou Aplicação não cadastrada! Cadastra?" )
            GOTO m_RecNo
            RETURN .F.
         ENDIF
      ENDIF
      WITH OBJECT cnSQL
         :QueryCreate()
         :QueryAdd( "BACONTA", mbaConta )
         :QueryAdd( "BAAPLIC", m_Aplic )
         nIdBancario := :QueryExecuteInsert( "JPBANCARIO" )
         :QueryAdd( "IDBANCARIO", StrZero( nIdBancario, 6 ) )
         jpbancario->( :DBFQueryExecuteInsert( "JPBANCARIO" ) )
         :QueryCreate()
         :QueryAdd( "BACONTA", mbaConta )
         :QueryAdd( "BAAPLIC", m_Aplic )
         :QueryAdd( "BADATBAN", Stod( "29991231" ) )
         :QueryAdd( "BADATEMI", Stod( "29991231" ) )
         :QueryAdd( "BAVALOR", 0 )
         nIdBancario := :QueryExecuteInsert( "JPBANCARIO" )
         :QueryAdd( "IDBANCARIO", StrZero( nIdBancario, 6 ) )
         jpbancario->( :DBFQueryExecuteInsert( "JPBANCARIO" ) )
      ENDWITH
   ELSE
      SEEK mbaConta + m_Aplic
      SEEK mbaConta + m_Aplic + Dtos( Date() ) SOFTSEEK
      SKIP -1
   ENDIF

   RETURN .T.

STATIC FUNCTION CadLanc( m_Tipo )

   LOCAL GetList := {}, m_MinDtBco, m_Aplic, mbaConta, m_Lin, m_DtEmi, m_DtBco, m_VlEnt
   LOCAL m_VlSai, m_Hist, m_Resumo, nRecNo
   LOCAL nIdBancario
   LOCAL cnSQL := ADOClass():new( AppConexao() )

   SET CURSOR ON
   WSave()
   m_Alterou    := .F.
   m_Lin        := Row()
   m_MinDtBco   := Stod( "29991231" )
   mbaConta     := jpbancario->baConta
   m_Aplic      := jpbancario->baAplic
   dDataInicial := iif( Type( "dDataInicial" ) != "D", Date() - 60, dDataInicial )
   DO CASE
   CASE m_Tipo == "EXCLUSAO"
      IF MsgYesNo( "Confirma exclusão?" )
         GravaOcorrencia( ,,"Exclusao BANCARIO de " + Dtoc( jpbancario->baDatEmi ) + ", " + Dtoc( jpbancario->baDatBan ) )
         m_DtEmi := jpbancario->baDatEmi
         m_DtBco := jpbancario->baDatBan
         jpbancario->( RecDelete() )
         SEEK mbaConta + m_Aplic + Dtos( m_DtBco ) + Dtos( m_DtEmi ) SOFTSEEK
         SKIP -1
         IF mbaConta != jpbancario->baConta .OR. m_Aplic != jpbancario->baAplic
            SEEK mbaConta + m_Aplic SOFTSEEK
         ENDIF
         m_Alterou  := .T.
      ENDIF
   CASE m_Tipo $ "ALTERACAO,INCLUSAO"
      DO WHILE .T.
         IF m_Tipo == "ALTERACAO"
            m_DtBco   := iif( jpbancario->baDatBan == Stod( "29991231" ), Ctod( "" ), jpbancario->baDatBan )
            m_DtEmi   := jpbancario->baDatEmi
            m_Resumo  := jpbancario->baResumo
            m_Hist    := jpbancario->baHist
            m_VlEnt   := iif( jpbancario->baValor < 0, 0, jpbancario->baValor  )
            m_VlSai   := iif( jpbancario->baValor > 0, 0, -jpbancario->baValor )
         ELSE
            Scroll( 5, 0, m_Lin, maxcol(), 1 )
            m_DtBco   := Ctod("")
            m_DtEmi   := Ctod("")
            m_Resumo  := EmptyValue( jpbancario->baResumo )
            m_Hist    := EmptyValue( jpbancario->baHist)
            m_VlEnt   := 0
            m_VlSai   := 0
         ENDIF
         wOpen( 10, 5, 20, 100, m_Tipo )
         @ 12, 12 SAY "Data do Banco"
         @ 12, 50 SAY "Data de Emissão"
         @ 13, 12 GET m_DtBco VALID OkData( @m_DtBco, dDataInicial )
         @ 13, 50 GET m_DtEmi VALID OkData( @m_DtEmi, dDataInicial )
         @ 15, 12 SAY "Resumo"
         @ 15, 30 SAY "Histórico"
         @ 16, 12 GET m_Resumo PICTURE "@K!" VALID ValidBancarioCCusto( @m_Resumo )
         @ 16, 30 GET m_Hist PICTURE "@K!" VALID ! Empty( m_Hist )
         @ 18, 12 SAY "Entrada"
         @ 18, 50 SAY "Saída"
         @ 19, 12 GET m_VlEnt PICTURE PicVal(14,2) VALID m_VlEnt >= 0 .AND. ReturnTrue( m_VlSai := iif( m_VlEnt != 0, 0, m_VlSai ) )
         @ 19, 50 GET m_VlSai PICTURE PicVal(14,2) VALID m_VlSai >= 0 WHEN m_VlEnt == 0
         Mensagem( "Digite campos, F9 Pesquisa, ESC abandona" )
         READ
         wClose()
         IF LastKey() == K_ESC
            EXIT
         ELSE
            WITH OBJECT cnSQL
               m_DtBco = iif( Empty( m_DtBco ), Stod( "29991231" ), m_DtBco )
               IF m_Tipo == "INCLUSAO"
                  IF m_Aplic != "S" .AND. m_Resumo = "APLIC"
                     ve_Conta( mbaConta, "S", .F. )
                     :QueryCreate()
                     :QueryAdd( "BACONTA", mbaConta )
                     :QueryAdd( "BAAPLIC", "S" )
                     :QueryAdd( "BADATBAN", m_DtBco )
                     :QueryAdd( "BADATEMI", m_DtEmi )
                     :QueryAdd( "BARESUMO", m_Resumo )
                     :QueryAdd( "BAHIST", m_Hist )
                     :QueryAdd( "BAVALOR", m_VlSai - m_VlEnt )
                     :QueryAdd( "BAINFINC", LogInfo() )
                     nIdBancario := :QueryExecuteInsert( "JPBANCARIO" )
                     :QueryAdd( "IDBANCARIO", StrZero( nIdBancario, 6 ) )
                     jpbancario->( :DBFQueryExecuteInsert( "JPBANCARIO" ) )
                     nRecNo := RecNo()
                     BARecalcula( mbaConta )
                     GOTO ( nRecNo )
                  ENDIF
                  :QueryCreate()
                  :QueryAdd( "BACONTA", mbaConta )
                  :QueryAdd( "BAAPLIC", m_Aplic )
                  :QueryAdd( "BADATBAN", m_DtBco )
                  nIdBancario := :QueryExecuteInsert( "JPBANCARIO" )
                  :QueryAdd( "IDBANCARIO", StrZero( nIdBancario, 6 ) )
                  jpbancario->( :DBFQueryExecuteInsert( "JPBANCARIO" ) )
                  m_Alterou  := .T.
                  m_MinDtBco := iif( m_MinDtBco < m_DtBco, m_MinDtBco, m_DtBco )
               ELSE
                  m_MinDtBco := iif( m_MinDtBco < jpbancario->baDatBan, m_MinDtBco, jpbancario->baDatBan )
               ENDIF
               :QueryCreate()
               IF jpbancario->baDatBan!= m_DtBco
                  :QueryAdd( "BADATBAN", m_DtBco )
                  m_MinDtBco = iif( m_MinDtBco < jpbancario->baDatBan, m_MinDtBco, jpbancario->baDatBan )
                  m_Alterou  := .T.
               ENDIF
               IF jpbancario->baDatEmi != m_DtEmi
                  :QueryAdd( "BADATEMI", m_DtEmi )
                  m_Alterou := .T.
               ENDIF
               IF jpbancario->baResumo != m_Resumo
                  :QueryAdd( "BARESUMO", m_Resumo )
                  m_Alterou := .T.
               ENDIF
               IF jpbancario->baHist != m_Hist
                  :QueryAdd( "BAHIST", m_Hist )
                  m_Alterou := .T.
               ENDIF
               IF jpbancario->baValor != ( m_VlEnt - m_VlSai )
                  :QueryAdd( "BAVALOR", m_VlEnt - m_VlSai )
                  m_Alterou := .T.
               ENDIF
               IF m_Alterou
                  :QueryAdd( "BAINFALT", LogInfo() )
                  jpbancario->( :DBFQueryExecuteUpdate( "JPBANCARIO" ) )
                  :QueryExecuteUpdate( "JPBANCARIO", "IDBANCARIO = " + NumberSQL( jpbancario->idBancario ) )
               ENDIF
            ENDWITH
         ENDIF
         IF m_Tipo == "ALTERACAO"
            EXIT
         ELSEIF LastKey() == 23
            KEYBOARD Chr( 205 )
            Inkey(0)
         ENDIF
      ENDDO
      IF LastKey() == K_ESC
         KEYBOARD Chr( 205 )
         Inkey(0)
      ENDIF
   ENDCASE
   IF m_Alterou
      nRecNo := RecNo()
      BARecalcula( jpbancario->baConta )
      GOTO nRecNo
      IF jpbancario->( Deleted() )
         jpbancario->( dbSkip( -1 ) )
      ENDIF
   ENDIF
   IF LastKey() == K_ESC
      KEYBOARD Chr(215)
      Inkey(0)
   ENDIF
   WRestore()

   RETURN .T.

STATIC FUNCTION DigFiltro()

   LOCAL oElement, m_Texto, m_Posi, GetList := {}

   m_Texto := ""
   FOR EACH oElement IN m_Filtro
      m_Texto += oElement + " "
   NEXT
   m_Texto = Pad( m_Texto, 200 )
   Scroll( 10, 0, 14, MaxCol(), 0 )
   @ 10, 0 to 14, MaxCol()
   @ 12, 1 to 12, MaxCol()-1
   @ 11, 1 SAY "Trechos de texto para filtro na apresentação dos dados"
   @ 13, 1 GET m_Texto PICTURE "@K!S75"
   READ
   IF LastKey() != K_ESC
      m_Filtro := {}
      m_Texto = Trim( m_Texto )
      DO WHILE Len( m_Texto ) != 0
         m_posi := At(" ",m_Texto+" ")
         AAdd( m_Filtro, Trim( Substr( m_Texto, 1, m_posi ) ) )
         m_Texto := lTrim( Substr( m_Texto, m_posi ) )
      ENDDO
      IF ! Filtro()
         GOTO TOP
      ENDIF
   ENDIF

   RETURN NIL

STATIC FUNCTION SomaFiltro()

   LOCAL m_RecNo := RecNo(), m_SomaEnt := 0, m_SomaSai := 0

   IF ! MsgYesNo( "Confirma a soma dos valores?" )
      RETURN NIL
   ENDIF
   GOTO TOP
   DO WHILE ! Eof()
      grafproc()
      IF ! Filtro()
         SKIP
         LOOP
      ENDIF
      IF jpbancario->baValor > 0
         m_SomaEnt += jpbancario->baValor
      ELSE
         m_SomaSai += jpbancario->baValor
      ENDIF
      SKIP
   ENDDO
   GOTO m_RecNo
   MsgExclamation( "Entradas:" + LTrim( Transform( m_SomaEnt, PicVal(14,2) ) ) + " Saídas:" + LTrim( Transform( m_SomaSai, PicVal(14,2) ) ) + ;
      " Dif:" + LTrim( Transform( m_SomaEnt + m_SomaSai, PicVal(14,2) ) ) )

   RETURN NIL

STATIC FUNCTION DigConta()

   LOCAL mbaConta := jpbancario->baConta, m_RecNo := RecNo(), m_NumConta := 1, m_NomeCta := {}, nCont

   GOTO TOP
   DO WHILE ! Eof()
      AAdd( m_NomeCta, jpbancario->baConta )
      SEEK jpbancario->baConta + "ZZZ" SOFTSEEK
   ENDDO
   IF Len( m_NomeCta ) == 0
      GOTO m_RecNo
   ELSE
      m_NumConta := hb_AScan( m_NomeCta, mbaConta )
      FOR nCont = 1 TO Len( m_NomeCta )
         m_NomeCta[ nCont ] := " " + Chr( 64 + nCont ) + " - " + m_NomeCta[ nCont ]
      NEXT
      WAchoice( 8, 9, m_NomeCta, @m_NumConta, "POSICIONAMENTO DE CONTA" )
      mbaConta = Substr( m_NomeCta[ m_NumConta ], 6 )
      SEEK mbaConta + "N" + Dtos( Date() ) SOFTSEEK
      SKIP -1
   ENDIF

   RETURN NIL

STATIC FUNCTION pBancoLancaLocaliza()

   LOCAL nCont, GetList := {}, m_RecNo := RecNo(), m_Struct, m_Sai

   THREAD STATIC m_Texto := " "

   wOpen( 5, 5, 10, MaxCol() - 1, "Texto a localizar" )
   m_Texto := Pad( m_Texto, 50 )
   // WSave( maxrow()-1, 0, maxrow(), maxcol() )
   // Mensagem( "Digite texto para localização afrente, ESC sai" )
   SET CURSOR ON
   @ 7, 7 GET m_Texto PICTURE "@K!"
   READ
   SET CURSOR OFF
   wClose()
   Mensagem()
   IF LastKey() != K_ESC
      Mensagem( "Aguarde... localizando texto afrente... ESC interrompe" )
      m_Texto = Trim(m_Texto)
      IF ! Eof()
         SKIP
      ENDIF
      m_Struct := dbStruct()
      m_Sai    := .F.
      DO WHILE ! m_Sai .AND. ! Eof()
         grafproc()
         FOR nCont = 1 TO fcount()
            m_Sai = ( Inkey() == K_ESC )
            DO CASE
            CASE m_Sai
            CASE m_Struct[ nCont, 2 ] == "N" ; m_Sai = ( m_Texto $ Str( FieldGet( nCont ) ) )
            CASE m_Struct[ nCont, 2 ] == "D" ; m_Sai = ( m_Texto $ Dtoc( FieldGet( nCont ) ) )
            CASE m_Struct[ nCont, 2 ] $ "CM" ; m_Sai = ( m_Texto $ Upper( FieldGet( nCont ) ) )
            OTHERWISE                        ; m_Sai = ( m_Texto $ Transform( FieldGet( nCont ), "" ) )
            ENDCASE
            IF m_Sai
               EXIT
            ENDIF
         NEXT
         IF m_Sai
            EXIT
         ENDIF
         SKIP
      ENDDO
      IF Eof()
         MsgWarning( "Nada foi localizado afrente!" )
         GOTO m_RecNo
      ELSE
         SKIP -1 // Porque retorna no registro seguinte
      ENDIF
   ENDIF
   KEYBOARD Chr( 205 )
   Inkey(0)

   RETURN NIL

FUNCTION BARecalcula( mbaConta ) // , dDataInicial, m_RecGeral )

   LOCAL aContaList := {}, oConta, nInicio, nFinal
   LOCAL cnSQL := ADOClass():New( AppConexao() )

   Mensagem( "Recalculando" )
   nInicio := hb_MilliSeconds()
   WITH OBJECT cnSQL
      :cSQL := "SELECT DISTINCT BACONTA, BAAPLIC" + ;
         " FROM JPBANCARIO" + ;
         iif( mbaConta == NIL, "", " WHERE BACONTA = " + StringSQL( mbaConta ) )
      :Execute()
      DO WHILE ! :Eof()
         AAdd( aContaList, { :String( "BACONTA" ), :String( "BAAPLIC" ) } )
         :MoveNext()
      ENDDO
      FOR EACH oConta IN aContaList
         :ExecuteCmd( "SET @SOMA = 0" )
         :ExecuteCmd( "UPDATE JPBANCARIO" + ;
            " INNER JOIN" + ;
               "( SELECT IDBANCARIO, BADATBAN, BADATEMI, BAVALOR," + ;
               " BASALDO, IF( BAVALOR < 0, 2, 1 ) AS ORDEM, @SOMA := @SOMA + BAVALOR AS SALDO" + ;
               " FROM JPBANCARIO" + ;
               " WHERE BACONTA = " + StringSQL( oConta[ 1 ] ) + ;
               " AND BAAPLIC = " + StringSQL( oConta[2 ] ) + ;
               " ORDER BY BACONTA, BAAPLIC, BADATBAN, BADATEMI, ORDEM, IDBANCARIO ) AS A" + ;
               " ON JPBANCARIO.IDBANCARIO = A.IDBANCARIO" + ;
            " SET JPBANCARIO.BASALDO = A.SALDO" + ;
            " WHERE JPBANCARIO.BACONTA = " + StringSQL( oConta[ 1 ] ) + " AND JPBANCARIO.BASALDO <> A.SALDO" )
      NEXT
      :ExecuteCmd( "SET @SOMA = NULL" )
      :ExecuteCmd( "SET @CONTA = NULL" )
      :ExecuteCmd( "SET @APLIC = NULL" )
      :ExecuteCmd( "SET @DATBAN = NULL" )
      :ExecuteCmd( "SET @DATEMI = NULL" )
      :ExecuteCmd( "UPDATE JPBANCARIO" + ;
         " INNER JOIN" + ;
            "( SELECT BACONTA, BAAPLIC, IDBANCARIO, BADATBAN, BADATEMI, BAVALOR, BAIMPSLD," + ;
            " IF( BAVALOR < 0, 2, 1 ) AS ORDEM, @C = BACONTA AS CONTA, @D = BAAPLIC AS APLIC," + ;
            " @E = BADATBAN AS DATBAN, @F = BADATEMI AS DATEMI," + ;
            " IF( BACONTA <> @CONTA OR BAAPLIC <> @APLIC OR BADATBAN <> @DATBAN OR " + ;
            " ( BADATEMI = '2999-12-31' AND BADATEMI <> @DATEMI ), 'N', 'S' ) AS IMPSLD" + ;
            " FROM JPBANCARIO" + ;
            iif( mbaConta == NIL, "", " WHERE BACONTA = " + StringSQL( mbaConta ) ) + ;
            " ORDER BY BACONTA DESC, BAAPLIC DESC, BADATBAN DESC, BADATEMI DESC, ORDEM DESC, " + ;
            " IDBANCARIO DESC ) AS A" + ;
            " ON JPBANCARIO.IDBANCARIO = A.IDBANCARIO" + ;
         " SET JPBANCARIO.BAIMPSLD = A.IMPSLD" + ;
         " WHERE JPBANCARIO.BAIMPSLD <> A.IMPSLD" + ;
         iif( mbaConta == NIL, "", " AND BACONTA = " + StringSQL( mbaConta ) ) )
      :ExecuteCmd( "SET @CONTA = NULL" )
      :ExecuteCmd( "SET @APLIC = NULL" )
      :ExecuteCmd( "SET @DATBAN = NULL" )
      :ExecuteCmd( "SET @DATEMI = NULL" )
      :CloseRecordset()
   ENDWITH
   nFinal := hb_MilliSeconds()
   MsgExclamation( Str( nFinal - nInicio ) )

   RETURN .T.

STATIC FUNCTION OkData( dData, dDataInicial )

   IF Empty( dData ) .OR. dData > dDataInicial
      RETURN .T.
   ENDIF

   RETURN MsgYesNo( "Data menor que limite! Aceita?" )

FUNCTION ValidBancarioConta( cConta )

   LOCAL lOk := .T.

   IF ! Encontra( cConta, "jpbancario" )
      MsgWarning( "Conta bancária não cadastrada no movimento atual" )
      lOk := .F.
   ENDIF

   RETURN lOk


É um fonte diferente de todos os outros.
No momento, representa quase o total dos DBFs, em tamanho.

Terminado esse fonte, reduz de 18MB pra 2MB em DBF !!!!
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18013
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

Meu modo de trabalho

Mensagempor JoséQuintas » 21 Jul 2020 22:07

A tela pra curiosidade

bancario.png


bancario2.png


Em ADO continua igual, sem novidade.
As duas estão no fonte, até terminar.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18013
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

Meu modo de trabalho

Mensagempor JoséQuintas » 21 Jul 2020 22:29

Na imagem deu pra ver que isto aqui não funcionou como eu pensava.

      :ExecuteCmd( "SET @SOMA = NULL" )
      :ExecuteCmd( "SET @CONTA = NULL" )
      :ExecuteCmd( "SET @APLIC = NULL" )
      :ExecuteCmd( "SET @DATBAN = NULL" )
      :ExecuteCmd( "SET @DATEMI = NULL" )
      :ExecuteCmd( "UPDATE JPBANCARIO" + ;
         " INNER JOIN" + ;
            "( SELECT BACONTA, BAAPLIC, IDBANCARIO, BADATBAN, BADATEMI, BAVALOR, BAIMPSLD," + ;
            " IF( BAVALOR < 0, 2, 1 ) AS ORDEM, @C = BACONTA AS CONTA, @D = BAAPLIC AS APLIC," + ;
            " @E = BADATBAN AS DATBAN, @F = BADATEMI AS DATEMI," + ;
            " IF( BACONTA <> @CONTA OR BAAPLIC <> @APLIC OR BADATBAN <> @DATBAN OR " + ;
            " ( BADATEMI = '2999-12-31' AND BADATEMI <> @DATEMI ), 'N', 'S' ) AS IMPSLD" + ;
            " FROM JPBANCARIO" + ;
            iif( mbaConta == NIL, "", " WHERE BACONTA = " + StringSQL( mbaConta ) ) + ;
            " ORDER BY BACONTA DESC, BAAPLIC DESC, BADATBAN DESC, BADATEMI DESC, ORDEM DESC, " + ;
            " IDBANCARIO DESC ) AS A" + ;
            " ON JPBANCARIO.IDBANCARIO = A.IDBANCARIO" + ;
         " SET JPBANCARIO.BAIMPSLD = A.IMPSLD" + ;
         " WHERE JPBANCARIO.BAIMPSLD <> A.IMPSLD" + ;
         iif( mbaConta == NIL, "", " AND BACONTA = " + StringSQL( mbaConta ) ) )
      :ExecuteCmd( "SET @CONTA = NULL" )
      :ExecuteCmd( "SET @APLIC = NULL" )
      :ExecuteCmd( "SET @DATBAN = NULL" )
      :ExecuteCmd( "SET @DATEMI = NULL" )
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18013
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

Meu modo de trabalho

Mensagempor JoséQuintas » 23 Jul 2020 02:16

30/12/2019  21:50               163 cthisto.dbf
30/12/2019  21:52               291 jprefcta.dbf
30/12/2019  21:50               355 ctlotes.dbf
30/12/2019  21:50               387 ctlanca.dbf
30/12/2019  21:50               483 jpcontabil.dbf
03/03/2020  02:44             2.799 jpfiscal.DBF
30/12/2019  21:50             5.335 jpempresa.dbf
13/07/2020  17:13             5.923 jpnumero.dbf
30/12/2019  21:50             6.691 ctplano.dbf
30/12/2019  21:52             7.416 jpuf.dbf
13/07/2020  17:13             9.997 jpconfi.dbf
10/07/2020  14:32           119.029 jptabel.dbf
30/12/2019  21:50           301.112 jpdolar.dbf
06/07/2020  11:25           314.624 jpsenha.dbf
03/03/2020  02:33         1.254.539 jpcidade.dbf
              15 arquivo(s)      2.029.144 bytes


UIA !!!!!
Reduziu pra 2MB em DBF
Sendo que desses 2MB, o jpcidade já está no MySQL.... o que reduz pra menos de 1MB !!!

Só que agora são os módulos fiscal e contábil....
O fiscal praticamente fora de uso, mas estou convertendo.
O contábil.... agora só instalando MySQL/MariaDB nos clientes que só usam o contábil.

Tá chegando ao fim.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18013
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

Anterior Próximo



Retornar para Contribuições, Dicas e Tutoriais

Quem está online

Usuários vendo este fórum: Google Adsense [Bot] e 18 visitantes


Ola Amigo, espero que meu site e forum tem lhe beneficiado, com exemplos e dicas de programacao.
Entao divulgue o link da Doacao abaixo para seus amigos e redes sociais ou faça uma doacao para o site forum...
MUITO OBRIGADO PELA SUA DOACAO!
Faça uma doação para o forum
cron
v
Olá visitante, seja bem-vindo ao Fórum Clipper On Line!
Efetue o seu login ou faça o seu Registro