Clipper On Line • Ver Tópico - Erros comuns - Clipper e Harbour
Página 1 de 2

Erros comuns - Clipper e Harbour

MensagemEnviado: 22 Jul 2019 19:28
por JoséQuintas
Tava aqui pensando com meus botões... kkkkk
O cara tá preocupado com GUI, com mouse, com Harbour, com não sei o que....
às vezes até troca pra LIB gráfica e resolve problemas sem nem saber que o problema era seu fonte.

DO WHILE ! RLock()
ENDDO


O computador tem mais o que fazer, principalmente o Windows e a rede.
Testar centenas de vezes por segundo se o registro tá liberado... isso é acabar com Windows e com a rede.
Vai resolver passando pra Harbour... aí ferrou de vez... ao invés de centenas de vezes por segundo, serão milhares de vezes por segundo.

Em Harbour.... ajuda muuuuuuito um Inkey(1)
Em Clipper.... ajuda o Inkey(1), mas ajuda mais alguma LIB pra liberar tempo para Windows, e mais ainda se for OSLIB e se ficar chamando OL_Yield() no intervalo de espera.

Explicação:
A cada teste, a rede é pesquisada, então há tráfego de informação pela rede.
O programa testando, está usando tempo de processamento do computador, e será que faz diferença centenas ou milhares de vezes por segundo?
OL_Yield() é uma função da OSLIB, é como se fosse uma pausa momentânea no processamento do aplicativo, e avisa para o Windows fazer alguma outra coisa enquanto está em pausa. Talvez milésimos de segundo, que seja, quanto mais chamar, mais tempo para o Windows, e menos tempo desperdiçado pelo aplicativo.

Erros comuns - Clipper e Harbour

MensagemEnviado: 22 Jul 2019 19:54
por JoséQuintas
Inkey(0)

Isso espera o usuário apertar alguma tecla?

ERRADÍSSIMO, com todas as letras maiúsculas.

Isso vale para teclado e mouse: na prática o programa fica vasculhando a cada milésimo/milionésimo de segundo se há alteração no teclado e mouse.
Em Harbour tudo bem, a linguagem de programação já está preparada pra não sobrecarregar o Windows.
Mas em Clipper.... naquela época isso de multitarefa não existia, por isso ele pode sobrecarregar o Windows só de ficar parado !!!!
Sério isso... é como se o programa estivesse a 1.000 por hora, quando na verdade está parado.

Por isso em Clipper é obrigatório usar alguma LIB pra liberar tempo ao Windows.
Eu sempre usei OSLIB.
Ela tem o modo automático e o modo manual.
O modo automático é pra onde não se tem opção de mexer - por exemplo a GETSYS original.
O modo manual permite liberar o máximo que puder.

É sério.

nKey := Inkey(0)


nKey := 0
DO WHILE nKey == 0
   OL_AutoYield()
ENDDO


Olhando assim, qual das duas consome mais CPU?
A segunda, porque fica processando o tempo todo?
Não... a primeira, porque fica vasculhando o teclado o tempo todo.
Na segunda há um "aviso para o Windows" de que o programa está parado e que pode aproveitar esse tempo extra, portanto o aplicativo acaba consumindo menos CPU.

Por isso nos meus aplicativos em Clipper eu usava um MyInkey() no lugar de Inkey(n), porque coloquei esse tratamento de "tempo para o Windows".
O Windows também lê/grava DBFs, roubar tempo do Windows é roubar tempo também do aplicativo, porque ele depende das informações do Windows.

E mouse é pior que teclado, consome mais CPU ainda !!!!!
Antes de pensar em colocar mouse no Clipper, pense nisso do uso de CPU.
Dá pra colocar? Sim, mas tem que deixar preparado pra não consumir muita CPU.

Novamente: o Harbour já é pra Windows, ele já tem tratamentos pra isso. Mas o Clipper... não existia Windows na época dele... era só o aplicativo e mais nada, por isso ele precisa de ajustes para o Windows...

Outro ponto importante:
consumir CPU também significa FRITAR PROCESSADOR.
Sim... se o Clipper usa 100% de CPU, significa que a CPU está na velocidade máxima... aonde ela ferve e pode até queimar.
O que salva hoje em dia é que temos processadores QuadCore, 4 núcleos, então o Clipper vai ferver só um núcleo, e já não corre tanto risco de fritar tudo

Saída para o Clipper:
alguma LIB pra "dar tempo ao Windows".
Alterar mais fundo, pra OL_Yield() da OSLIB por exemplo.... talvez pra curiosidade.

Melhor avaliar direito se é melhor gastar tempo com o Clipper pra resolver essas coisas, ou se é melhor gastar esse tempo pra já usar Harbour aonde tudo isso está resolvido.
Isso depende de cada um.
Eu usava isso antes de 2008, compensou, porque ANTES dessa época o Harbour ainda tinha alguns bugs.

Erros comuns - Clipper e Harbour

MensagemEnviado: 22 Jul 2019 20:13
por JoséQuintas
NTX ou CDX?

Duas diferenças básicas entre NTX e CDX

- NTX é de apenas um índice. Pra ter 5 índices são 5 arquivos
- CDX é múltiplo: basta 1 único arquivo

Por acaso deixou de usar índices pra não estourar o limite de arquivos?
Já imaginou precisar de 50 índices para um único arquivo?

Vamos lá, um exemplo fictício: 10 arquivos com 30 índices cada.
Com NTX: 1 DBF + 30 NTX = 31 arquivos X 10 = 310 arquivos - já era.... o DOS não aceita isso
Com CDX: 1 DBF + 1 CDX = 2 arquivos X 10 = 20 arquivos - até o DOS aceita

abertura de um arquivo desses em NTX:

USE ARQUIVO
SET INDEX TO ntx1, ntx2, ntx3, ntx4, ntx5, ntx6, ntx8, ntx9, ntx10, ntx11, ntx12, ntx13, ntx14, .....mais 16 ainda
xi... faltou o ntx7... fud... vai corromper índice

em CDX

USE ARQUIVO
SET INDEX TO arquivo // já abriu os 30 índices em arquivo.CDX

Bom... essa foi a primeira vantagem: quantidade de arquivos envolvidos, segurança na abertura de arquivos/índices, mais longe das limitações do sistema operacional, menos arquivos pro sistema operacional "tomar conta", menos arquivos corrompidos, etc. etc. etc

A segunda: índice CDX é compactado

Isso significa menos espaço em disco.... e.... menos tráfego de rede

No caso do Clipper convém destacar o seguinte:

- Diz a literatura que CDX do Clipper 5.2 não é muito bom, melhor usar SIXCDX com ele, já o CDX do Clipper 5.3 é mais eficiente (as RDDs são de terceiros, apesar de fazerem parte do Clipper, e cada versão era de um "fabricante" diferente)
- O uso de CDX tem mais recursividade. Pode ser interessante usar o Blinker e indicar isso no linqueditor, antes de adotar o CDX

Nota: lembrando que se o aplicativo Clipper funcionou até hoje, mais interessante passar pra Harbour primeiro, e só depois pensar no CDX.

Erros comuns - Clipper e Harbour

MensagemEnviado: 22 Jul 2019 20:32
por JoséQuintas
Memória:

Harbour nem precisa comentar. em 32 bits limita a 4GB de memória, e em 64 bits nem me preocupo em saber.

O Clipper já teve o PLINK86, o RTLINK, o EXOSPACE e o BLINKER.
Acho que todos eram produtos de terceiros, mesmo vindo no Clipper.

Aqui o RTLINK 7, que comprei na época, que liberava mais memória

2010-06-04-DSC00143.JPG


Assim como o RTLINK, o BLINKER também tem versão independente.
Não confunda o que faz parte do Clipper com o que é vendido separado.

PLINK86: limitado a 640KB de memória, mas permitindo o uso de overlay, pra carregar um pedaço do programa por vez

RTLINK: uso de overlay automático. Por ser automático, carregar um pedaço do programa por vez, facilitou, mas ainda limitado aos 640KB de memória

RTLINK7 separado: mais opções de até dividir o Clipper em pedaços e liberar mais memória

EXOSPACE: sem overlays, e uso de até 8MB de memória. Na prática nem tanto, mas de qualquer jeito muito mais do que os outros linqueditores

BLINKER: híbrido, permitindo overlay ou não, e até DLL !!!! Até 16MB de memória, tranquilidade em compilar.

Importante também:

O Clipper permite o uso de arquivo CLP, e muita gente fez/faz uso disso, ou até do Clipper "puxar" automático os outros PRGs.
Isso é errado, porque o OBJ fica grande e precisa ser carregado todo de uma vez.
Lembram acima: overlay... rtlink... carregar um pedaço de cada vez... pois é... criando um OBJ com tudo junto, está impedindo que isso aconteça, está atrapalhando o Clipper ao invés de ajudar.

O default do Harbour é -m, pra compilar cada fonte separado.
Quem precisa muito disso é o Clipper. No final, quem sente dificuldade com isso é porque faz/fazia errado no Clipper.
O EXE final é o mesmo, a diferença é "durante" a execução.

do jeito errado:

arquivo.clp
prg1.prg
prg2.prg
prg3.prg

clipper @arquivo.clp
rtlink fi arquivo.obj

do jeito certo:

clipper prg1 -m
clipper prg2 -m
clipper prg3 -m
rtlink fi prg1, prg2, prg3

Nota: aqui mostrando referente ao parâmetro -m, não significa que seja o único necessário

Em Harbour os limites são maiores, mas nada impede de continuar fazendo igual.
Pode ser bom até pra LIBs, pra quando linqueditar trazer somente o necessário.

Erros comuns - Clipper e Harbour

MensagemEnviado: 22 Jul 2019 20:49
por JoséQuintas
Faltou no post anterior, talvez até melhor ter ficado separado:

O BLINKER permite usar até 16MB de memória, linqueditando no modo EXTENDED.
Isso o produto em separado, não o produto que vém no Clipper.

Não é automático, só faz isso se colocar os comandos pra fazer isso.

Importante também:

nem todas as LIBs permitem o uso em modo EXTENDED.
Se ainda usa Clipper, se achou interessante o Blinker, linquedite primeiro pra confirmar se suas LIBs aceitam esse modo EXTENDED.

Este ainda compensa usar no Clipper, porque altera apenas o comando pra linqueditar, e deixa o Clipper aproveitar muuuita memória.

Não lembro se era no W95/W98.... não se podia misturar EXEs de EXOSPACE e BLINKER na mesma máquina, porque a forma de configurar memória era diferente.
Uma vez a memória se configurando automático para EXOSPACE, não funcionava para BLINKER, e vice-versa.
Na prática já não lembro mais os detalhes, ou se era mesmo BLINKER e EXOSPACE, ou se precisava DEVICE=algumacoisa.sys...
Eu lembro do DOS=HIGH,UMB, que liberava um pouco mais de memória, por mover parte do command.com pra acima de 640KB.
Lembro do DEVICE=HIMEM.SYS, mas já não lembro mais pra que servia.... e hoje em dia nem importa mais...
E o DEVICE=COUNTRY.SYS, pra configurar a codepage do DOS... que o Clipper tinha arquivos pra codepage também...

Erros comuns - Clipper e Harbour

MensagemEnviado: 22 Jul 2019 21:06
por JoséQuintas
clipper.png


Que pena que não entendi isso antes....

Olhem lá no Clipper: parâmetro W - habilitar warnings

Significa permitir que o Clipper mostre alertas sobre possíveis problemas !!! possível fonte errado !!!

Em outras palavras: o default do Clipper era NÃO se importar se estava certo ou errado, ele podia te ajudar mas o default sempre foi SEM ajuda, SEM avisos.

O Harbour e o XHarbour também tem isso.

Vai de cada um, vai de fazer isso agora... ou pelo menos para fontes novos...

Convém destacar: mostra lá ano de 1995.... 24 anos atrás já existia essa ajuda

Erros comuns - Clipper e Harbour

MensagemEnviado: 22 Jul 2019 23:38
por JoséQuintas
Sobre a compilação usando -n

Isso é para desprezar o nome do arquivo em disco, e usar somente o conteúdo.

exemplo:

----programa.prg---
PROCEDURE yx

Se compilar esse fonte com -n, no EXE vai entrar a PROCEDURE yx
Já se compilar sem -n, no EXE vão entrar duas procedures: programa e yx, o nome do prg acaba sendo uma rotina

Se dentro do prg não especificar nada, então o fonte recebe o nome do PRG, e com -n não é aceito porque o conteúdo não tem nome.

Muita gente deixa isso pra depois, mas.... tenho uma novidade:
o Clipper tem limites, mas o Harbour não. O Harbour pode ser usado pra corrigir o PRG !!!
Este é um erro de muitos, esquecer de usar o Harbour pra ajudar.

Vamos lá... o que precisa?
Pegar o nome do PRG, e colocar dentro do fonte, como PROCEDURE...

#include "directry.ch"
PROCEDURE Main

LOCAL aList, aDetails, cNomePrg, cNomeProc, cTxt

   aList := Directory( "*.prg" )
   FOR EACH aDetails IN aList
      cNomePrg := aDetails[ F_NAME ]
      cNomeProc := Substr( cNomePrg, 1, At( ".", cNomePrg ) - 1 )
      cTxt := "PROCEDURE " + cNomePrg + hb_Eol()
      cTxt += hb_Eol()
      cTxt += MemoRead( cNomePrg )
      hb_MemoWrit( cNomePrg, cTxt )
   NEXT

   RETURN


Pronto, resolvido.
Vai pegar cada fonte, e usar o nome do PRG pra colocar a declaração de PROCEDURE dentro do arquivo.
O nome da procedure é o mesmo nome do arquivo, mas sem a extensão ".prg"
Agora é executar o programa de ajuste, e depois retirar dos lugares que não precisava.

Neste caso... o erro é esquecer de usar a programação para se ajudar, pra acelerar "as coisas".

Erros comuns - Clipper e Harbour

MensagemEnviado: 23 Jul 2019 12:05
por JoséQuintas
PACK

Parece que muita gente não presenciou isso.
Em Clipper acontecia de um PACK duplicar/triplicar registros.
Não era muito comum, mas acontecia.

Campo MEMO

EU TIVE esse problema.
Só de existir um campo memo no arquivo, o índice gerava erro interno.
INDEX ON código TO arquivo

O campo memo nem fazia parte do índice, e gerava erro no uso, logo após ter sido criado.
Ao remover o campo memo, tudo resolvido.

Nunca procurei saber sobre isso no Harbour, porque já estava acostumado a não usar mais.

Erros comuns - Clipper e Harbour

MensagemEnviado: 27 Jul 2019 11:38
por JoséQuintas
Em outro post "enxerguei" outro erro comum:

fonte/DO WHILE linguição - muitas linhas de fonte !!!!

Ambiente GUI obriga a dividir em partes, acho que muitos atribuem a facilidade da programação em GUI, e nem percebem que uma grande diferença é essa !!!!

O programador começa com DO WHILE, um dentro do outro, e vai, e o fonte fica com milhares de linhas com um único DO WHILE.
A partir daí, deixa de formatar o fonte pra ele ficar mais magrinho, o fonte fica ainda pior de entender.
A partir daí, vai poluindo e enchendo cada vez mais de anotações, piorando mais a cada vez.

E o linguição numa janela do EDIT do DOS então... já era... fica difícil enxergar tudo e consertar alguma coisa.

Divida em partes/assuntos, vai ficar extremamente mais simples.

Uma opção é usar variáveis PRIVATE... fazer o quê.... e outra é passar variáveis por referência, ou até mesmo #define com constantes - mas é importantíssimo compilar usando -w3 -es2 pra não ter imprevistos.

Aliás... reforçando isso: se tem um fonte de trocentas mil linhas...

- primeiro adote compilação -w3 -es2, dá trabalho, mas vale a pena
- só depois divida em partes, porque a compilação -w3 -es2 vai estar te ajudando a evitar fazer besteira

Vai querer evitar as mensagens de erro, e vai começar a fazer certo só por causa disso.
E com o tempo vai entender que é realmente o modo certo de se fazer.

Erros comuns - Clipper e Harbour

MensagemEnviado: 27 Jul 2019 12:25
por JoséQuintas
Aproveitar o fonte que foi postado.
É de principiante... principiante pode... programador com mais de 20 anos de experiência não pode...
Mas é um bom exemplo pra mostrar como organizar, e como usar -w3 -es2 pra ajudar na organização.


Do While .t.
   Clear

   Set Date to British
   Set Century On
  // Set Delimiters On
//   Set Delimiters to "[]"

   //VARIAVEIS GERAIS
   nOrdemServico         := 1 //contador autom tico
   cNomeCliente          := space(50)
   cNomeTecnico          := space(40)
   cDescricaoEquipamento := space(50)
   dDataOrdemServico     := Date()
   dDataCompra           := Ctod("")
   nLinha                := 11
   cTipoOrdem            := space(1)
   nProdutoFinalG        := 0
   nServicoFinalG        := 0
   cTotal                := "Total a pagar:"

   //VARIAVEIS GARANTIA

   //VARIAVEIS VALOR TOTAL
   nProdutoFinal  := 0
   nServicoFinal  := 0
   nComissaoTotal := 0

   @ 01,01 say "ORDEM DE SERVICO N:"
   @ 01,22 say nOrdemServico
   @ 03,01 say "Cliente:"
   @ 04,01 say "Tecnico:"
   @ 05,01 say "Descricao do Equipamento:"
   @ 06,01 say "Data da Compra:"
   @ 06,30 say "Data do Servi‡o:"
   @ 07,01 say "Digite P para produto ou S para servico:"

   @ 03,10 Get cNomeCliente          Picture "@!" Valid !Empty(cNomeCliente)
   @ 04,10 Get cNomeTecnico          Picture "@!" Valid !Empty(cNomeTecnico)
   @ 05,27 Get cDescricaoEquipamento Picture "@!" Valid !Empty(cDescricaoEquipamento)
   @ 06,17 Get dDataCompra                        Valid !Empty(dDataCompra)
   @ 06,47 say dDataOrdemServico
   @ 07,41 Get cTipoOrdem            Picture "@!" Valid ((cTipoOrdem = "P") .or. (cTipoOrdem = "S"))
   Read

   //VARIAVEL NOME PRODUTO
   cDescricaoProduto := space(30)
   Do While cTipoOrdem = "P"

      //VARIAVEIS PRODUTO
      nQuantidade       := 0
      nPrecoUnitario    := 0
      nDescontoProduto  := 0

   // Total com  Desconto :Total - (Total*Desconto/100)

      @ 09,01 say "Descricao do Produto:"
      @ 09,23 Get cDescricaoProduto    Picture "@!"                 Valid !Empty(cDescricaoProduto)

      @ 10,01 say "Quantidade"
      @ 10,14 say "Preco Unit."
      @ 10,35 say "Desconto"
      @ 10,50 say "Total"
      @ 16,01 say "Total Final:"

      @ nLinha,01 Get nQuantidade      Picture "99999"               Valid nQuantidade      >= 1
      @ nLinha,14 Get nPrecoUnitario   Picture "@E 9,999,999,999.99" Valid nPrecoUnitario   >= 1
      @ nLinha,35 Get nDescontoProduto Picture "99999.99"            Valid nDescontoProduto >= 0
      Read

      //TOTAL UNITARIO
      nTotalProduto := (nPrecoUnitario * nQuantidade)-((nPrecoUnitario * nQuantidade)*(nDescontoProduto/100))
      @ nLinha,50 say +AllTrim(Transform(nTotalProduto, "@E 999,999,999,999.99"))

      //TOTAL FINAL
      nProdutoFinal := nProdutoFinal + nTotalProduto

      If nLinha > 16
         @ nLinha,01 Clear to 15,70
         nLinha := 11
      Endif

      nGarantiaProduto := dDataOrdemServico - dDataCompra // 2 anos (730 ou 731 dias)

      If nGarantiaProduto <= 731
         @ 17,01 say cTotal
         @ 17,16 say nProdutoFinalG Picture "@E 9,999.99"
      else
         @ 17,01 say cTotal
         @ 17,16 say nProdutoFinal  Picture "@E 999,999,999.99"
      Endif

      If LastKey() == 27
         nAviso1 := Alert("O que deseja fazer?",{"Finalizar e inicar outro chamado","Apenas Finalizar", "Cancelar"})
         If nAviso1 = 1
            @ 16,13 say nProdutoFinal Picture "@E 999,999,999.99"
            @ 07,01 say "Digite P para produto ou S para servico:"
            @ 07,41 Get cTipoOrdem            Picture "@!" Valid ((cTipoOrdem = "P") .or. (cTipoOrdem = "S"))
            Read
         elseif nAviso1 = 2
            @ 16,13 say nProdutoFinal Picture "@E 999,999,999.99"
         else
            exit
         Endif
      Endif

      nLinha++
   Enddo

   //VARIAVEL NOME SERVICO
   cDescricaoServico := space(30)
   Do While cTipoOrdem = "S"

      //VARIAVEIS SERVI€O
      nDescontoServico  := 0
      nComissaoTecnico  := 0
      nValorServico     := 0

      @ 09,01 say "Descricao do Servico:"
      @ 09,23 Get cDescricaoServico Picture "@!"   Valid !Empty(cDescricaoServico)
      Read

      @ 10,01 say "Valor"
      @ 10,25 say "Desconto"
      @ 10,35 say "Comissao"
      @ 10,55 say "Total"
      @ 16,01 say "Total Final:"

      @ nLinha,01 Get nValorServico     Picture "@E 999,999,999.99" Valid nValorServico    >=1
      @ nLinha,25 Get nDescontoServico  Picture "99999.99"          Valid nDescontoServico >= 1
      @ nLinha,35 Get nComissaoTecnico  Picture "99999.99"          Valid nComissaoTecnico >= 0
      Read

      nTotalServico := nValorServico + (nValorServico*(nComissaoTecnico/100)) - (nValorServico*(nDescontoServico/100))
      @ nLinha,55 say +AllTrim(Transform(nTotalServico, "@E 999,999,999,999.99"))

      nComissaoTotal := nComissaoTotal + (nValorServico*(nComissaoTecnico/100))
      nServicoFinal := nServicoFinal + nTotalServico

      @ 18,01 say "Total Comissao:"
      @ 18,18 say Transform (nComissaoTotal, "@E 999,999.99")

      If nLinha > 16
         @ nLinha,01 Clear to 15,70
         nLinha := 11
      Endif

      If LastKey() == 27
         nAviso2 := Alert("Deseja finalizar a ordem de servico?",{"Sim","Nao"})
         If nAviso2 = 1
         @ 16,13 say nServicoFinal Picture "@E 999,999,999.99"
         else
            loop
         Endif
      Endif

      nGarantiaServico := dDataOrdemServico - dDataCompra // 1 ano  (365 ou 366 dias)

      If nGarantiaServico <= 366
         @ 17,01 say cTotal
         nProdutoFinalG := 0
         @ 17,16 say nServicoFinalG Picture "@E 9,999.99"
      else
         @ 17,01 say cTotal
         @ 17,16 say nServicoFinal  Picture "@E 999,999,999.99"
      Endif
      nLinha++
   Enddo
   If LastKey() == 27
      nAviso := Alert("Deseja mesmo cancelar?", {"Sim","Nao"})
      If nAviso = 1
         Exit
      Endif
   EndIf

   nOrdemServico += 1
   nOrdemServico++

Enddo


Qualquer erro que for procurar... complicou... tem que ficar paginando tudo pra cima e pra baixo.
Vamos começar compilando com -w3 -es2.

d:\temp>hbmk2 codos -w3 -es2
hbmk2: Processing environment options: -comp=mingw
hbmk2: Processing configuration: d:\harbour\bin\hbmk.hbc
Harbour 3.4.0dev (8289a47fd1) (2019-06-07 14:14)
Copyright (c) 1999-2019, https://github.com/JoseQuintas/harbour34/
Compiling 'codos.prg'...
codos.prg(4) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(4) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(12) Warning W0001 Ambiguous reference 'NORDEMSERVICO'
codos.prg(13) Warning W0001 Ambiguous reference 'CNOMECLIENTE'
codos.prg(14) Warning W0001 Ambiguous reference 'CNOMETECNICO'
codos.prg(15) Warning W0001 Ambiguous reference 'CDESCRICAOEQUIPAMENTO'
codos.prg(16) Warning W0001 Ambiguous reference 'DDATAORDEMSERVICO'
codos.prg(17) Warning W0001 Ambiguous reference 'DDATACOMPRA'
codos.prg(18) Warning W0001 Ambiguous reference 'NLINHA'
codos.prg(19) Warning W0001 Ambiguous reference 'CTIPOORDEM'
codos.prg(20) Warning W0001 Ambiguous reference 'NPRODUTOFINALG'
codos.prg(21) Warning W0001 Ambiguous reference 'NSERVICOFINALG'
codos.prg(22) Warning W0001 Ambiguous reference 'CTOTAL'
codos.prg(30) Warning W0001 Ambiguous reference 'NPRODUTOFINAL'
codos.prg(31) Warning W0001 Ambiguous reference 'NSERVICOFINAL'
codos.prg(32) Warning W0001 Ambiguous reference 'NCOMISSAOTOTAL'
codos.prg(35) Warning W0001 Ambiguous reference 'NORDEMSERVICO'
codos.prg(43) Warning W0001 Ambiguous reference 'CNOMECLIENTE'
codos.prg(43) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(43) Warning W0001 Ambiguous reference 'CNOMECLIENTE'
codos.prg(43) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(44) Warning W0001 Ambiguous reference 'CNOMETECNICO'
codos.prg(44) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(44) Warning W0001 Ambiguous reference 'CNOMETECNICO'
codos.prg(44) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(45) Warning W0001 Ambiguous reference 'CDESCRICAOEQUIPAMENTO'
codos.prg(45) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(45) Warning W0001 Ambiguous reference 'CDESCRICAOEQUIPAMENTO'
codos.prg(45) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(46) Warning W0001 Ambiguous reference 'DDATACOMPRA'
codos.prg(46) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(46) Warning W0001 Ambiguous reference 'DDATACOMPRA'
codos.prg(46) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(47) Warning W0001 Ambiguous reference 'DDATAORDEMSERVICO'
codos.prg(48) Warning W0001 Ambiguous reference 'CTIPOORDEM'
codos.prg(48) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(48) Warning W0001 Ambiguous reference 'CTIPOORDEM'
codos.prg(48) Warning W0001 Ambiguous reference 'CTIPOORDEM'
codos.prg(48) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(49) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(49) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(49) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(53) Warning W0001 Ambiguous reference 'CDESCRICAOPRODUTO'
codos.prg(54) Warning W0001 Ambiguous reference 'CTIPOORDEM'
codos.prg(57) Warning W0001 Ambiguous reference 'NQUANTIDADE'
codos.prg(58) Warning W0001 Ambiguous reference 'NPRECOUNITARIO'
codos.prg(59) Warning W0001 Ambiguous reference 'NDESCONTOPRODUTO'
codos.prg(65) Warning W0001 Ambiguous reference 'CDESCRICAOPRODUTO'
codos.prg(65) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(65) Warning W0001 Ambiguous reference 'CDESCRICAOPRODUTO'
codos.prg(65) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(73) Warning W0001 Ambiguous reference 'NLINHA'
codos.prg(73) Warning W0001 Ambiguous reference 'NQUANTIDADE'
codos.prg(73) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(73) Warning W0001 Ambiguous reference 'NQUANTIDADE'
codos.prg(73) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(74) Warning W0001 Ambiguous reference 'NLINHA'
codos.prg(74) Warning W0001 Ambiguous reference 'NPRECOUNITARIO'
codos.prg(74) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(74) Warning W0001 Ambiguous reference 'NPRECOUNITARIO'
codos.prg(74) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(75) Warning W0001 Ambiguous reference 'NLINHA'
codos.prg(75) Warning W0001 Ambiguous reference 'NDESCONTOPRODUTO'
codos.prg(75) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(75) Warning W0001 Ambiguous reference 'NDESCONTOPRODUTO'
codos.prg(75) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(76) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(76) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(76) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(79) Warning W0001 Ambiguous reference 'NPRECOUNITARIO'
codos.prg(79) Warning W0001 Ambiguous reference 'NQUANTIDADE'
codos.prg(79) Warning W0001 Ambiguous reference 'NPRECOUNITARIO'
codos.prg(79) Warning W0001 Ambiguous reference 'NQUANTIDADE'
codos.prg(79) Warning W0001 Ambiguous reference 'NDESCONTOPRODUTO'
codos.prg(79) Warning W0001 Ambiguous reference 'NTOTALPRODUTO'
codos.prg(80) Warning W0001 Ambiguous reference 'NLINHA'
codos.prg(80) Warning W0001 Ambiguous reference 'NTOTALPRODUTO'
codos.prg(83) Warning W0001 Ambiguous reference 'NPRODUTOFINAL'
codos.prg(83) Warning W0001 Ambiguous reference 'NTOTALPRODUTO'
codos.prg(83) Warning W0001 Ambiguous reference 'NPRODUTOFINAL'
codos.prg(85) Warning W0001 Ambiguous reference 'NLINHA'
codos.prg(86) Warning W0001 Ambiguous reference 'NLINHA'
codos.prg(86) Warning W0001 Ambiguous reference 'NLINHA'
codos.prg(87) Warning W0001 Ambiguous reference 'NLINHA'
codos.prg(90) Warning W0001 Ambiguous reference 'DDATAORDEMSERVICO'
codos.prg(90) Warning W0001 Ambiguous reference 'DDATACOMPRA'
codos.prg(90) Warning W0001 Ambiguous reference 'NGARANTIAPRODUTO'
codos.prg(92) Warning W0001 Ambiguous reference 'NGARANTIAPRODUTO'
codos.prg(93) Warning W0001 Ambiguous reference 'CTOTAL'
codos.prg(94) Warning W0001 Ambiguous reference 'NPRODUTOFINALG'
codos.prg(96) Warning W0001 Ambiguous reference 'CTOTAL'
codos.prg(97) Warning W0001 Ambiguous reference 'NPRODUTOFINAL'
codos.prg(101) Warning W0001 Ambiguous reference 'NAVISO1'
codos.prg(102) Warning W0001 Ambiguous reference 'NAVISO1'
codos.prg(103) Warning W0001 Ambiguous reference 'NPRODUTOFINAL'
codos.prg(105) Warning W0001 Ambiguous reference 'CTIPOORDEM'
codos.prg(105) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(105) Warning W0001 Ambiguous reference 'CTIPOORDEM'
codos.prg(105) Warning W0001 Ambiguous reference 'CTIPOORDEM'
codos.prg(105) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(106) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(106) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(106) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(107) Warning W0001 Ambiguous reference 'NAVISO1'
codos.prg(108) Warning W0001 Ambiguous reference 'NPRODUTOFINAL'
codos.prg(115) Warning W0001 Ambiguous reference 'NLINHA'
codos.prg(115) Warning W0001 Ambiguous reference 'NLINHA'
codos.prg(119) Warning W0001 Ambiguous reference 'CDESCRICAOSERVICO'
codos.prg(120) Warning W0001 Ambiguous reference 'CTIPOORDEM'
codos.prg(123) Warning W0001 Ambiguous reference 'NDESCONTOSERVICO'
codos.prg(124) Warning W0001 Ambiguous reference 'NCOMISSAOTECNICO'
codos.prg(125) Warning W0001 Ambiguous reference 'NVALORSERVICO'
codos.prg(129) Warning W0001 Ambiguous reference 'CDESCRICAOSERVICO'
codos.prg(129) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(129) Warning W0001 Ambiguous reference 'CDESCRICAOSERVICO'
codos.prg(129) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(130) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(130) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(130) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(138) Warning W0001 Ambiguous reference 'NLINHA'
codos.prg(138) Warning W0001 Ambiguous reference 'NVALORSERVICO'
codos.prg(138) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(138) Warning W0001 Ambiguous reference 'NVALORSERVICO'
codos.prg(138) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(139) Warning W0001 Ambiguous reference 'NLINHA'
codos.prg(139) Warning W0001 Ambiguous reference 'NDESCONTOSERVICO'
codos.prg(139) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(139) Warning W0001 Ambiguous reference 'NDESCONTOSERVICO'
codos.prg(139) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(140) Warning W0001 Ambiguous reference 'NLINHA'
codos.prg(140) Warning W0001 Ambiguous reference 'NCOMISSAOTECNICO'
codos.prg(140) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(140) Warning W0001 Ambiguous reference 'NCOMISSAOTECNICO'
codos.prg(140) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(141) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(141) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(141) Warning W0001 Ambiguous reference 'GETLIST'
codos.prg(143) Warning W0001 Ambiguous reference 'NVALORSERVICO'
codos.prg(143) Warning W0001 Ambiguous reference 'NVALORSERVICO'
codos.prg(143) Warning W0001 Ambiguous reference 'NCOMISSAOTECNICO'
codos.prg(143) Warning W0001 Ambiguous reference 'NVALORSERVICO'
codos.prg(143) Warning W0001 Ambiguous reference 'NDESCONTOSERVICO'
codos.prg(143) Warning W0001 Ambiguous reference 'NTOTALSERVICO'
codos.prg(144) Warning W0001 Ambiguous reference 'NLINHA'
codos.prg(144) Warning W0001 Ambiguous reference 'NTOTALSERVICO'
codos.prg(146) Warning W0001 Ambiguous reference 'NCOMISSAOTOTAL'
codos.prg(146) Warning W0001 Ambiguous reference 'NVALORSERVICO'
codos.prg(146) Warning W0001 Ambiguous reference 'NCOMISSAOTECNICO'
codos.prg(146) Warning W0001 Ambiguous reference 'NCOMISSAOTOTAL'
codos.prg(147) Warning W0001 Ambiguous reference 'NSERVICOFINAL'
codos.prg(147) Warning W0001 Ambiguous reference 'NTOTALSERVICO'
codos.prg(147) Warning W0001 Ambiguous reference 'NSERVICOFINAL'
codos.prg(151) Warning W0001 Ambiguous reference 'NCOMISSAOTOTAL'
codos.prg(153) Warning W0001 Ambiguous reference 'NLINHA'
codos.prg(154) Warning W0001 Ambiguous reference 'NLINHA'
codos.prg(154) Warning W0001 Ambiguous reference 'NLINHA'
codos.prg(155) Warning W0001 Ambiguous reference 'NLINHA'
codos.prg(159) Warning W0001 Ambiguous reference 'NAVISO2'
codos.prg(160) Warning W0001 Ambiguous reference 'NAVISO2'
codos.prg(161) Warning W0001 Ambiguous reference 'NSERVICOFINAL'
codos.prg(167) Warning W0001 Ambiguous reference 'DDATAORDEMSERVICO'
codos.prg(167) Warning W0001 Ambiguous reference 'DDATACOMPRA'
codos.prg(167) Warning W0001 Ambiguous reference 'NGARANTIASERVICO'
codos.prg(169) Warning W0001 Ambiguous reference 'NGARANTIASERVICO'
codos.prg(170) Warning W0001 Ambiguous reference 'CTOTAL'
codos.prg(171) Warning W0001 Ambiguous reference 'NPRODUTOFINALG'
codos.prg(172) Warning W0001 Ambiguous reference 'NSERVICOFINALG'
codos.prg(174) Warning W0001 Ambiguous reference 'CTOTAL'
codos.prg(175) Warning W0001 Ambiguous reference 'NSERVICOFINAL'
codos.prg(177) Warning W0001 Ambiguous reference 'NLINHA'
codos.prg(177) Warning W0001 Ambiguous reference 'NLINHA'
codos.prg(180) Warning W0001 Ambiguous reference 'NAVISO'
codos.prg(181) Warning W0001 Ambiguous reference 'NAVISO'
codos.prg(186) Warning W0001 Ambiguous reference 'NORDEMSERVICO'
codos.prg(186) Warning W0001 Ambiguous reference 'NORDEMSERVICO'
codos.prg(187) Warning W0001 Ambiguous reference 'NORDEMSERVICO'
codos.prg(187) Warning W0001 Ambiguous reference 'NORDEMSERVICO'


Normal, declarar variáveis....

Erros comuns - Clipper e Harbour

MensagemEnviado: 27 Jul 2019 12:28
por JoséQuintas
PROCEDURE Main

LOCAL nOrdemServico, cNomeCliente, cNomeTecnico, cDescricaoEquipamento
LOCAL dDataOrdemServico, dDataCompra, nLinha, cTipoOrdem
LOCAL nProdutoFinalG, nServicoFinalG, cTotal, nComissaoTecnico
LOCAL nValorServico, nDescontoServico, nServicoFinal, nComissaoTotal
LOCAL nTotalServico, nAviso2, nGarantiaServico, nAviso, cDescricaoServico
LOCAL nDescontoProduto, nPrecoUnitario, nQuantidade, nGarantiaProduto
LOCAL nAviso1, nProdutoFinal, cDescricaoProduto, nTotalProduto
LOCAL GetList := {}


Variáveis declaradas

Compiling 'codos.prg'...
codos.prg(200) Warning W0032 Variable 'GETLIST' is assigned but not used in function 'MAIN(10)'
codos.prg(200) Warning W0032 Variable 'NPRODUTOFINALG' is assigned but not used in function 'MAIN(180)'
codos.prg(200) Warning W0032 Variable 'NORDEMSERVICO' is assigned but not used in function 'MAIN(196)'


Nem é tão grande o fonte, mas confirmar sobre essas linhas serem inúteis vai ser trabalhoso.

Erros comuns - Clipper e Harbour

MensagemEnviado: 27 Jul 2019 12:35
por JoséQuintas
Até que nem tanto.....

Do While .t.
   nOrdemServico := 1
...
   nOrdemServico += 1
   nOrdemServico++
Enddo


Se está sendo sempre atribuído 1 ao número, somar 1 não serve pra nada...
Estar somando 1 duas vezes não foi indicado como erro, porque pode acontecer...

Legal aqui. Só de declarar variáveis já encontramos erro no fonte.
Como eu já disse, -w3 -es2 avisa sobre possíveis problemas, é como um ajudante conferindo o fonte , mas baseado nas informações que colocamos no fonte - declaração de variáveis.

Erros comuns - Clipper e Harbour

MensagemEnviado: 27 Jul 2019 16:59
por JoséQuintas
apenas didivido, e variáveis PRIVATE.

MEMVAR nOrdemServico
MEMVAR cNomeCliente, cNomeTecnico, cDescricaoEquipamento
MEMVAR dDataOrdemServico, dDataCompra, nLinha, cTipoOrdem
MEMVAR nProdutoFinalG, nServicoFinalG, cTotal, nComissaoTecnico
MEMVAR nValorServico, nDescontoServico, nServicoFinal, nComissaoTotal
MEMVAR nTotalServico, nAviso2, nGarantiaServico, nAviso, cDescricaoServico
MEMVAR nDescontoProduto, nPrecoUnitario, nQuantidade, nGarantiaProduto
MEMVAR nAviso1, nProdutoFinal, cDescricaoProduto, nTotalProduto, nDigita
MEMVAR nAlert

PROCEDURE Main

   PRIVATE nOrdemServico := 1
   PRIVATE cNomeCliente          := Space(50)
   PRIVATE cNomeTecnico          := Space(40)
   PRIVATE cDescricaoEquipamento := Space(50)
   PRIVATE dDataOrdemServico     := Date()
   PRIVATE dDataCompra           := Ctod("")
   PRIVATE nLinha                := 11
   PRIVATE cTipoOrdem            := Space(1)
   PRIVATE nProdutoFinalG        := 0
   PRIVATE nServicoFinalG        := 0
   PRIVATE cTotal                := "Total a pagar:"

   CLS

   SET DATE to British
   SET CENTURY ON
   // Set Delimiters On
   //   Set Delimiters to "[]"

   DO WHILE .T.

      DigitaOS()
      nAlert := Alert( "Digita mais OS", { "Sim", "Nao" } )
      IF nAlert = 2
         EXIT
      ENDIF
      nOrdemServico += 1
   ENDDO

   RETURN

STATIC FUNCTION DigitaOS()

   LOCAL GetList := {}
   //VARIAVEIS GERAIS

   //VARIAVEIS GARANTIA

   //VARIAVEIS VALOR TOTAL
   nProdutoFinal  := 0
   nServicoFinal  := 0
   nComissaoTotal := 0

   @ 01,01 SAY "ORDEM DE SERVICO N:"
   @ 01,22 SAY nOrdemServico
   @ 03,01 SAY "Cliente:"
   @ 04,01 SAY "Tecnico:"
   @ 05,01 SAY "Descricao do Equipamento:"
   @ 06,01 SAY "Data da Compra:"
   @ 06,30 SAY "Data do Servi‡o:"
   @ 07,01 SAY "Digite P para produto ou S para servico:"

   @ 03,10 GET cNomeCliente          PICTURE "@!" Valid !Empty(cNomeCliente)
   @ 04,10 GET cNomeTecnico          PICTURE "@!" Valid !Empty(cNomeTecnico)
   @ 05,27 GET cDescricaoEquipamento PICTURE "@!" Valid !Empty(cDescricaoEquipamento)
   @ 06,17 GET dDataCompra                        Valid !Empty(dDataCompra)
   @ 06,47 SAY dDataOrdemServico
   @ 07,41 GET cTipoOrdem            PICTURE "@!" Valid ((cTipoOrdem = "P") .OR. (cTipoOrdem = "S"))
   READ

   DO WHILE .T.
      nAlert := Alert( "Digita Produto", "Digita Servico", "Encerra" )
      IF nDigita = 3
         EXIT
      ENDIF
      IF nDigita != 1 .AND. nDigita != 2
         LOOP
      ENDIF
      IF nDigita == 2
         DigitaProduto()
      ELSE
         DigitaServico()
      ENDIF
   ENDDO

   RETURN NIL

STATIC FUNCTION DigitaProduto()

   LOCAL GetList := {}

   //VARIAVEL NOME PRODUTO
   cDescricaoProduto := Space(30)
   DO WHILE cTipoOrdem = "P"

      //VARIAVEIS PRODUTO
      nQuantidade       := 0
      nPrecoUnitario    := 0
      nDescontoProduto  := 0

      // Total com  Desconto :Total - (Total*Desconto/100)

      @ 09,01 SAY "Descricao do Produto:"
      @ 09,23 GET cDescricaoProduto    PICTURE "@!"                 Valid !Empty(cDescricaoProduto)

      @ 10,01 SAY "Quantidade"
      @ 10,14 SAY "Preco Unit."
      @ 10,35 SAY "Desconto"
      @ 10,50 SAY "Total"
      @ 16,01 SAY "Total Final:"

      @ nLinha,01 GET nQuantidade      PICTURE "99999"               Valid nQuantidade      >= 1
      @ nLinha,14 GET nPrecoUnitario   PICTURE "@E 9,999,999,999.99" Valid nPrecoUnitario   >= 1
      @ nLinha,35 GET nDescontoProduto PICTURE "99999.99"            Valid nDescontoProduto >= 0
      READ

      //TOTAL UNITARIO
      nTotalProduto := (nPrecoUnitario * nQuantidade)-((nPrecoUnitario * nQuantidade)*(nDescontoProduto/100))
      @ nLinha,50 SAY +AllTrim(Transform(nTotalProduto, "@E 999,999,999,999.99"))

      //TOTAL FINAL
      nProdutoFinal := nProdutoFinal + nTotalProduto

      IF nLinha > 16
         @ nLinha,01 CLEAR TO 15,70
         nLinha := 11
      ENDIF

      nGarantiaProduto := dDataOrdemServico - dDataCompra // 2 anos (730 ou 731 dias)

      IF nGarantiaProduto <= 731
         @ 17,01 SAY cTotal
         @ 17,16 SAY nProdutoFinalG PICTURE "@E 9,999.99"
      ELSE
         @ 17,01 SAY cTotal
         @ 17,16 SAY nProdutoFinal  PICTURE "@E 999,999,999.99"
      ENDIF

      IF LastKey() == 27
         nAviso1 := Alert("O que deseja fazer?",{"Finalizar e inicar outro chamado","Apenas Finalizar", "Cancelar"})
         IF nAviso1 = 1
            @ 16,13 SAY nProdutoFinal PICTURE "@E 999,999,999.99"
            @ 07,01 SAY "Digite P para produto ou S para servico:"
            @ 07,41 GET cTipoOrdem            PICTURE "@!" Valid ((cTipoOrdem = "P") .OR. (cTipoOrdem = "S"))
            READ
         ELSEIF nAviso1 = 2
            @ 16,13 SAY nProdutoFinal PICTURE "@E 999,999,999.99"
         ELSE
            EXIT
         ENDIF
      ENDIF

      nLinha++
   ENDDO

   RETURN NIL

STATIC FUNCTION DigitaServico()

   LOCAL GetList := {}

   //VARIAVEL NOME SERVICO
   cDescricaoServico := Space(30)
   DO WHILE cTipoOrdem = "S"

      //VARIAVEIS SERVI€O
      nDescontoServico  := 0
      nComissaoTecnico  := 0
      nValorServico     := 0

      @ 09,01 SAY "Descricao do Servico:"
      @ 09,23 GET cDescricaoServico PICTURE "@!"   Valid !Empty(cDescricaoServico)
      READ

      @ 10,01 SAY "Valor"
      @ 10,25 SAY "Desconto"
      @ 10,35 SAY "Comissao"
      @ 10,55 SAY "Total"
      @ 16,01 SAY "Total Final:"

      @ nLinha,01 GET nValorServico     PICTURE "@E 999,999,999.99" Valid nValorServico    >=1
      @ nLinha,25 GET nDescontoServico  PICTURE "99999.99"          Valid nDescontoServico >= 1
      @ nLinha,35 GET nComissaoTecnico  PICTURE "99999.99"          Valid nComissaoTecnico >= 0
      READ

      nTotalServico := nValorServico + (nValorServico*(nComissaoTecnico/100)) - (nValorServico*(nDescontoServico/100))
      @ nLinha,55 SAY +AllTrim(Transform(nTotalServico, "@E 999,999,999,999.99"))

      nComissaoTotal := nComissaoTotal + (nValorServico*(nComissaoTecnico/100))
      nServicoFinal := nServicoFinal + nTotalServico

      @ 18,01 SAY "Total Comissao:"
      @ 18,18 SAY Transform (nComissaoTotal, "@E 999,999.99")

      IF nLinha > 16
         @ nLinha,01 CLEAR TO 15,70
         nLinha := 11
      ENDIF

      IF LastKey() == 27
         nAviso2 := Alert("Deseja finalizar a ordem de servico?",{"Sim","Nao"})
         IF nAviso2 = 1
            @ 16,13 SAY nServicoFinal PICTURE "@E 999,999,999.99"
         ELSE
            LOOP
         ENDIF
      ENDIF

      nGarantiaServico := dDataOrdemServico - dDataCompra // 1 ano  (365 ou 366 dias)

      IF nGarantiaServico <= 366
         @ 17,01 SAY cTotal
         //nProdutoFinalG := 0
         @ 17,16 SAY nServicoFinalG PICTURE "@E 9,999.99"
      ELSE
         @ 17,01 SAY cTotal
         @ 17,16 SAY nServicoFinal  PICTURE "@E 999,999,999.99"
      ENDIF
      nLinha++
   ENDDO

   RETURN NIL


O ideal, agora que está dividido, é organizar as variáveis.
Por exemplo....
variáveis de produto, só interessam pra rotina de produtos.
variáveis de serviço, só interessam pra rotina de serviços.
E por aí vai.
Acaba sendo não só a divisão de rotinas, mas a divisão das variáveis, cada uma no seu assunto.
E menos variáveis... menos complicação no fonte. (serão as mesmas de antes, mas cada uma aonde é utilizada)

Erros comuns - Clipper e Harbour

MensagemEnviado: 27 Jul 2019 17:02
por JoséQuintas
Chamar atenção para uma coisa:
Ao compilar com -w3 -es2, apareceram os erros com variáveis.
Se eu fosse mexer antes disso, poderia parecer que as alterações que causaram problema.
E aí... dá-lhe voltar o fonte anterior pra procurar o que foi mexido.... e lá vai perda de tempo.
Por isso é bom começar pela análise das variáveis, antes de dividir em partes.
O que pareceu perder tempo, é ganho de tempo, porque só tem caminho de ir em frente, sem precisar voltar atrás.

Erros comuns - Clipper e Harbour

MensagemEnviado: 27 Jul 2019 17:07
por JoséQuintas
Sobre outro erro do GetList....
É interessante também porque todos esquecem disto.

LOCAL GetList := {}
CLEAR


Isso dá erro em compilação -w3 -es2

Porque?
CLEAR

CLEAR equivale a CLS; GetList := {}
Com isso, estava duas vezes atribuindo valor a GetList.

Pra limpar a tela é CLS.
Pra limpar tela e também gets pendentes é CLEAR.

Erros comuns - Clipper e Harbour

MensagemEnviado: 27 Jul 2019 17:12
por JoséQuintas
Aliás....
vindo de std.ch

#command CLEAR                   => CLEAR SCREEN ; CLEAR GETS

#command CLEAR SCREEN               => CLS

#command CLS                        => Scroll() ; SetPos( 0, 0 )

#command CLEAR GETS     => ReadKill( .T. ) ; GetList := {} ; ( GetList )

Erros comuns - Clipper e Harbour

MensagemEnviado: 27 Jul 2019 20:20
por JoséQuintas
Pronto, agora separado por assunto....
TODAS as variáveis LOCAIS.

Assunto 1: configurar ambiente, repetir digitação de OS, somar 1 a cada OS

#include "inkey.ch"

PROCEDURE Main

   LOCAL nNumero := 1, nOpc

   SetMode( 35, 100 )
   CLS
   SET DATE    BRITISH
   SET CENTURY ON
   SetColor( "W/N,N/W,,,W/N" )

   DO WHILE .T.
      DigitaOS( nNumero )
      nOpc := Alert( "Digita mais OS", { "Sim", "Nao" } )
      IF LastKey() == K_ESC .OR. nOpc = 2
         EXIT
      ENDIF
      nNumero += 1
   ENDDO

   RETURN


Assunto 2: a digitação da OS.

STATIC FUNCTION DigitaOS( nNumero )

   LOCAL GetList := {}
   LOCAL nTotServico := 0, nTotProduto := 0, nTotComissao := 0, nTotDesconto := 0
   LOCAL cCliente := Space(30), cTecnico := Space(30)
   LOCAL cEquipamento := Space(30), dDataCompra := Ctod("")
   LOCAL dDataOrdem := Ctod(""), nOpc, nIdade

   @ 01,01 SAY "ORDEM DE SERVICO:" GET nNumero      PICTURE "999999" WHEN .F.
   @ 03,01 SAY "Cliente:"          GET cCliente     PICTURE "@!" Valid ! Empty( cCliente )
   @ 04,01 SAY "Tecnico:"          GET cTecnico     PICTURE "@!" Valid ! Empty( cTecnico )
   @ 05,01 SAY "Equipamento:"      GET cEquipamento PICTURE "@!" Valid ! Empty( cEquipamento )
   @ 06,01 SAY "Data da Compra:"   GET dDataCompra               Valid ! Empty( dDataCompra )
   @ 06,30 SAY "Data do Servico:"  GET dDataOrdem                valid ! Empty( dDataOrdem )
   READ

   nIdade := dDataOrdem - dDataCompra

   DO WHILE .T.
      nOpc := Alert( "Opção", { "Digita Produto", "Digita Servico", "Encerra" } )
      IF LastKey() == K_ESC .OR. nOpc = 3
         EXIT
      ENDIF
      IF nOpc != 1 .AND. nOpc != 2
         LOOP
      ENDIF
      IF nOpc == 2
         DigitaProduto( @nTotProduto, @nTotServico, @nTotComissao, @nTotDesconto, nIdade )
      ELSE
         DigitaServico( @nTotServico, @nTotServico, @nTotComissao, @nTotDesconto, nIdade )
      ENDIF
   ENDDO

   RETURN NIL


Assunto 3: a digitação de produto

STATIC FUNCTION DigitaProduto( nTotProduto, nTotServico, nTotComissao, nTotDesconto, nIdade )

   LOCAL GetList := {}
   LOCAL nLinha  := 11
   LOCAL cDescricao := Space(30)
   LOCAL nQtde, nValor, nDesconto, nTotal, nComissao := 0

   DO WHILE .T.
      nQtde := nValor := nDesconto := nTotal := 0
      @ nLinha, 01 SAY "Descricao do Produto:" GET cDescricao PICTURE "@!" Valid ! Empty( cDescricao )
      @ nLinha + 1, 01 SAY "Quantidade" GET nQtde   PICTURE "99999" Valid nQtde >= 1 .AND. Calcula( nQtde, nValor, nDesconto, nComissao, @nTotal )
      @ nLinha + 1, 14 SAY "Preco Unit." GET nValor PICTURE "999,999.99" Valid nValor >= 1 .AND. Calcula( nQtde, nValor, nDesconto, nComissao, @nTotal )
      @ nLinha + 1, 35 SAY "Desconto" GET nDesconto PICTURE "999.99" Valid nDesconto >= 0 .AND. Calcula( nQtde, nValor, nDesconto, nComissao, @nTotal )
      @ nLinha + 1, 50 SAY "Total" GET nTotal       PICTURE "999,999.99" WHEN .F.
      READ
      IF LastKey() == K_ESC
         EXIT
      ENDIF
      nTotProduto += nTotal
      nTotDesconto += ( nQtde * nValor * nDesconto / 100 )
      MostraTotais( nTotProduto, nTotServico, nTotComissao, nTotDesconto, nIdade )
      nLinha += 2
      IF nLinha > 16
         @ 11, 1 CLEAR TO 15,70
         nLinha := 11
      ENDIF
   ENDDO

   RETURN NIL


Assunto 5: digitar serviços

STATIC FUNCTION DigitaServico( nTotProduto, nTotServico, nTotComissao, nTotDesconto, nIdade )

   LOCAL GetList := {}, nLinha := 11, cDescricao := Space(30)
   LOCAL nDesconto, nComissao, nValor, nTotal

   DO WHILE .T.

      nDesconto := nComissao := nValor := nTotal := 0

      @ nLinha,     01 SAY "Descricao do Servico:" GET cDescricao PICTURE "@!"      Valid ! Empty( cDescricao )
      @ nLinha + 1, 01 SAY "Valor"    GET nValor    PICTURE "999,999.99" Valid nValor >=1 .AND. Calcula( 1, nValor, nDesconto, nComissao, @nTotal )
      @ nLinha + 1, 25 SAY "Desconto" GET nDesconto PICTURE "999.99"          Valid nDesconto >= 1 .AND. Calcula( 1, nValor, nDesconto, nComissao, @nTotal )
      @ nLinha + 1, 35 SAY "Comissao" GET nComissao PICTURE "999.99"          Valid nComissao >= 0 .AND. Calcula( 1, nValor, nDesconto, nComissao, @nTotal )
      @ nLinha + 1, 55 SAY "Total"    GET nTotal    WHEN .F.
      READ
      IF LastKey() == K_ESC
         EXIT
      ENDIF
      nTotServico  += nTotal
      nTotComissao += ( nValor * nComissao / 100 )
      nTotDesconto += ( nValor * nDesconto / 100 )
      MostraTotais( nTotProduto, nTotServico, nTotComissao, nTotDesconto, nIdade )
      nLinha += 1
      IF nLinha > 16
         @ 11, 1 CLEAR TO 15,70
         nLinha := 11
      ENDIF
   ENDDO

   RETURN NIL


Assunto 6: pra seguir um padrão, uma rotina pra mostrar totais

STATIC FUNCTION MostraTotais( nTotProduto, nTotServico, nTotComissao, nTotDesconto, nIdade )

   IF nIdade <= 365
      nTotServico := 0
   ENDIF
   IF nIdade <= 731
      nTotProduto := 0
   ENDIF

   @ 16, 0 SAY "Totais:"
   @ Row(), Col() + 2 SAY "Prod:"
   @ Row(), Col() + 2 SAY nTotProduto  PICTURE "999,999.99"
   @ Row(), Col() + 2 SAY "Serv:"
   @ Row(), Col() + 2 SAY nTotServico  PICTURE "999,999.99"
   @ Row(), Col() + 2 SAY "Com:"
   @ Row(), Col() + 2 SAY nTotComissao PICTURE "999,999.99"
   @ Row(), Col() + 2 SAY "Des:"
   @ Row(), Col() + 2 SAY nTotDesconto PICTURE "999.999.99"
   @ Row(), Col() + 2 SAY "Tot:"
   @ Row(), Col() + 2 SAY nTotProduto + nTotServico + nTotComissao PICTURE "999,999.99"

   RETURN NIL


Rotina a mais: o cálculo de cada produto

STATIC FUNCTION Calcula( nQtde, nValor, nComissao, nDesconto, nTotal )

   nTotal := ( nValor * nQtde * ( nComissao / 100 ) ) - ( nValor * nQtde * ( nDesconto / 100 ) )

   RETURN .T.


Não sei ao certo como ficariam os valores na garantia, ou a comissão do técnico, então não alterei cada valor.
Um detalhe a mais sobre separar em rotinas é: NOMES de variáveis. Acabamos podendo usar mesmo nome em rotinas diferentes.

Pra não ter que passar tanta variável entre as rotinas, talvez mais interessante transformar tudo em ARRAY, e usar #define pra não cometer erros de digitação.

Erros comuns - Clipper e Harbour

MensagemEnviado: 27 Jul 2019 21:09
por JoséQuintas
Até que ficou interessante.
Já teve programador por aqui perguntando como fazer algo assim...
Todo mundo sempre tem algo a ensinar, não importa se é programador experiente ou principiante.

Lembrando: o fonte inicial com o funcionamento veio pronto, eu apenas fiz ajustes.
Nota: aqui usando array

codos.prg
(5.43 KiB) Baixado 85 vezes


digitaos.png

Erros comuns - Clipper e Harbour

MensagemEnviado: 27 Jul 2019 21:22
por JoséQuintas
Por causa da garantia não saíram os valores dos produtos.
Por erro na Picture, o desconto também não saiu.

Erros comuns - Clipper e Harbour

MensagemEnviado: 29 Jul 2019 12:22
por JoséQuintas
Lembrei de outro erro comum: versão separada

É...
O cara quer passar de Clipper pra Harbour, ou Xharbour pra Harbour, ou console pra GUI, ou RDD, ou outra coisa...
Aí cria um programa em separado.... e vai atualizando... ou não atualiza... e para tudo...
Depois começa de novo... para tudo...
E fica assim por anos, sem sair do lugar.

Faça um teste sem separado, pra ver se funciona, depois coloque no aplicativo e coloque pra rodar nos clientes.
Deu certo? Ok. Veja se dá pra melhorar, e vá em frente, sempre colocando pra rodar nos clientes.
Com isso, tudo vai estar sempre vivo e atualizado.

Quantas vezes começou e parou?
Há quanto vém começando e parando?
Se estivesse instalado nos clientes... estaria apenas continuando, e não tendo que começar do zero.
Já ENXERGUE tudo que pode dar certo ou errado nisso que fez, pra ver se pode continuar indo em frente.

Isso é o incentivo que falta: ir em frente, sair do lugar, nem que seja um passo de cada vez.

Resolveu uma coisa em um dia: ótimo... isso já poderia fazer parte de todos os aplicativos. vai ver TODOS indo em frente.

Tem um montão de fonte pra resolver isso... anos e anos e continuam...
Se resolver apenas uma coisa, em todos os fontes, as pendências vão se reduzindo a cada ano.
E está com aquilo na cabeça, pronto pra ser aplicado, "craque" pra fazer aquilo, é a melhor hora pra mexer em tudo.

Se for alterar uma coisa de cada vez, em cada fonte, em cada aplicativo, vai ter esquecido o que fez no primeiro, seria como começar tudo de novo.
É aproveitar que uma alteração está na cabeça, que está "na ponta da língua", e aplicar em tudo.
Vai ficar mais "craque" nessa alteração, vai virar um "expert" nisso, e depois vê a próxima alteração.
Na próxima, aproveita pra corrigir alguma da anterior que deixou passar.

Erros comuns - Clipper e Harbour

MensagemEnviado: 29 Jul 2019 12:32
por JoséQuintas
Não atualizar o sistema automático.

Acho que nos dias de hoje isso pode ser considerado um erro, um grande erro.

Quantas vezes no cliente trocar versão? centenas?
quanto tempo pra ir no cliente, trocar, e voltar? 1 hora no mínimo?
São centenas de horas fazendo isso.
Não pode gastar menos horas e preparar isso automático?

1) Atualização do EXE

Coloque pra fazer, em um cliente, teste, confirme, depois mais de um.

2) Backup

Comece colocando um backup, isso é um ponto importante.
Deixe rodando, confira, tudo ok, backup funcionando....
Coloque em mais clientes... tudo ok... então próxima etapa.

3) Comece a atualização automática.

Pode ser o controle, sem atualizar nada, só pra confirmar se o backup vai funcionar.
Ok... funcionou, comece com atualizações bem básicas pra ver se funciona.
Ok... vai testando mais complicado

Erros comuns - Clipper e Harbour

MensagemEnviado: 29 Jul 2019 12:46
por JoséQuintas
Ainda no caso anterior:

Pode começar só você podendo fazer isso.
Primeiro você faz presencial, assim pode consertar se precisar.

Veja o que acontece, e vai melhorando.
Até que isso possa acontecer sem você por perto.
Qualquer problema.... aquelas trocentas horas em vários clientes... vão ser reduzidas a um único cliente eventual.
E já acerta o automático sobre esse caso eventual.

E por aí vai...

Como faz tudo isso?
Ué... Você é quem sabe o que o seu aplicativo precisa, apenas coloque isso dentro do programa.

Cada cliente é de um jeito....
Precisa ser cada um de um jeito ? Não dá pra deixar todos iguais?
Se der pra fazer isso, menos trabalho, mais fácil saber o que precisa fazer.

Mesma coisa que já falei antes: uma coisa de cada vez.
Precisa padronizar pastas/atalhos/etc? então comece padronizando, um de cada vez.

NUNCA tenha pressa.
Vai preparando os ambientes, vai organizando tudo, nos clientes mas PRINCIPALMENTE NA SUA MÁQUINA, porque dela sai tudo.
Um pouco por dia, o importante é ir em frente, vai preparando.

Erros comuns - Clipper e Harbour

MensagemEnviado: 29 Jul 2019 13:00
por JoséQuintas
PATH RELATIVO

Isso muitos esquecem, e bagunçam tudo.
Pra que isso?

USE H:\SISTEMA\ARQUIVOS\cliente.dbf

Não é melhor

USE ARQUIVOS\cliente.dbf

Agora pode instalar local, em rede, no cliente numa pasta, em sua máquina em outra, pode até ter duas pastas no cliente uma com a versão velha e outra com a versão nova.

o PATH RELATIVO é o PATH partindo da pasta atual como referência.
A pasta atual... tanto faz, não importa mais.

Este é um erro cometido até por algumas LIBs... que enchem de parâmetros só por causa de usar nome fixo, e complicam a vida dos usuários.

Fugir um pouco pra falar sobre HBC.

HMGEXTENDED.HBC
incpaths=include
libpaths=lib

se o HBC estiver assim.... tanto faz a pasta da HMG Extended, ele sempre vai indicar as pastas dela
No caso do HBC, ele indica a pasta RELATIVA
A partir daí, só indicar no projeto (ou no Harbour) aonde pesquisar o HBC.
Muuuito melhor do que ficar configurando variáveis para pasta include, pasta lib, etc., que podem ser diferentes para cada usuário. Aonde o usuário instalar é aonde vai funcionar - fim.

Faça no aplicativo igual: o PATH atual sendo o PATH base de tudo, sem nem mesmo importar aonde está o EXE.
Se tem subpastas, só indicar arquivo\cliente.dbf, nota\arquivo.xml, etc. etc.

E veja se usa versão atualizada de Harbour.
Isso já teve problema em versões antigas, talvez a 3.0 ou a 3.1, quando usada lib gráfica.

Também tem função pra retornar o nome do EXE com path e tudo... também pode ser usado como referência: a pasta do EXE.