Página 1 de 2
Rotina de codigo automático
Enviado: 24 Out 2008 16:44
por Josmar dos Santos
Ola pessol, to precisando de uma rotina de colocar codigo automatico em um determinado campo caracter. Gostaria se possível, uma rotina que rode em rede. Se alguém tiver, eu agradeceria muito, pois to precisando com certa urgência.
Um abraço a todos....
:xau
Re: Rotina de codigo automático
Enviado: 24 Out 2008 17:14
por Maligno
Se for um código automático que apenas dê uma identidade única a certo objeto, sugiro o uso de um número aleatório. Eu faço isso e nunca tive problema. Funciona em modo local ou rede. O único detalhe é que, na (remota) possibilidade de já existir um número igual ao que foi gerado, antes deve ser feita uma pesquisa no arquivo. Se já existir, é só gerar outro. Eu uso a função Rand() da CATools. Mas uso apenas a parte fracionária e sobre ela gero o CRC32() que me dá no retorno uma string de tamanho menor e fixo. Essa função tenho no meu site, caso queira.
Re: Rotina de codigo automático
Enviado: 24 Out 2008 23:13
por gvc
Veja sobre semaforo em:
https://pctoledo.org/forum/viewto ... f=1&t=2762
Lá, alende de uma dica do Mestre Maligno, tem uma modesta contribuição minha, que controla número sequencial para pedidos.
Re: Rotina de codigo automático
Enviado: 01 Dez 2008 13:55
por Josmar dos Santos
Volto novamente a falar desse topico, porque ainda não tive sucesso, ja colhi algumas informações, mas a verdade e que preciso adaptar essa rotina a minha atual. O problema e que esse sistema que to tentando manipilar ja foi feito aos dez anos atras. O pior e que nessa epoca ele foi feito pelo miro3. Acho q vocês ja notarao isso ! Ja consegui fazer algumas alterações...mas tem muitos problemas a ser resolvido q ate agora nao tive sucesso ! Por exemplo: quando dou um enter, ele entra no cadastro, mas quando dou "esc" e volto novamente, ele pula o codigo automatico de dois em dois. O pior de tuudo, e que ele nem registra na dbu !
Coloco as duas rotinas, uma que funciona sem problema em ntx e a outra que estou tentando adaptar ao cdx. É lógico que se os colegas tiverem alguma outra soluçao sem usar essa rotina ...vai ser bem aceito.
Código: Selecionar todos
* -> tentando adaptar para cdx
function carreg01( tipo_acao )
me_mo := "[memo]"
if tipo_acao = inclusao
goto bott
skip
endif
cod_cli := clientes->cod_cli
nom_cli := clientes->nom_cli
dat_cli := clientes->dat_cli
val_cli := clientes->val_cli
obs_c := clientes->obs_c
if tipo_acao = inclusao
area_arq := alltrim( str( select(), 5 ) )
set order to 1
goto bott
cod_cli := (cod_cli,5)
while .t.
seek (cod_cli)
if eof()
append blank
replace all cod_cli with strzero(recno(),5)
commit
unlock
exit
else
cod_cli := strzero(cod_cli,5)
endif
enddo
sele &area_arq
endif
* - > funcao adaptada para ntx
function carreg01( tipo_acao ) //funcao que carrega os dados para o banco de dados
me_mo := "[memo]"
if tipo_acao = inclusao
goto bott
skip
endif
cod_cli := clientes->cod_cli
nom_cli := clientes->nom_cli
dat_cli := clientes->dat_cli
val_cli := clientes->val_cli
obs_c := clientes->obs_c
*-> Codigo automatico
if tipo_acao = inclusao
area_arq := alltrim( str( select(), 5 ) ) // ->busca o prg que cria os arquivos no bando de dados
set order to 1
goto bott
cod_cli:= strzero( val( field->cod_cli) + 1, 5 )
sele 100
while .t.
seek padr( "002" + cod_cli, 100 ) // 002 -> indice de controle do ntx e 100 - > indice de controle da rede
if eof()
if adireg( 0 )
replace dados with padr( "002" + cod_cli, 100 )
commit
unlock
aadd( re_gistros, recn() ) //funcao que registra o arquivo
endif
exit
else
cod_cli:= strzero( val( cod_cli) + 1, 5 )
endif
enddo
sele &area_arq //->busca o prg que cria os arquivos no bando de dados
endif
um abraço a todos
:xau
Re: Rotina de codigo automático
Enviado: 01 Dez 2008 19:01
por Ademir
Oi Josmar, boa tarde !
Acho que o mais fácil pra vc resolver esse problema seria o seguinte:
Antes de gravar o codigo, bloqueie o arquivo. Em seguida, dê um go bott, some mais 1 ao codigo atribuindo esse valor a uma variavel e em seguida grave o registro com esse codigo. Logo após, claro, dê um dbcommit() e desbloqueie o arquivo. Isso lhe dará a certeza de que o código é válido, pois bloqueando o arquivo, somente o usuario que confirmou a inclusão primeiro terá a prioridade. Se outro usuario tentar isso, quando conseguir bloquear o arquivo já pegará um novo codigo e assim por diante. Vale lembrar que essa operação toda é muito rapida. Para bloquear esse arquivo, vc poderá usar um contador de tempo com uns 5 segundos mais ou menos. E bloqueando o arquivo vc nem precisa dar seek para saber se está cadastrado ou não. Seria algo mais ou menos assim:
Código: Selecionar todos
if acao=´Inclusao´
if arqlock(5)
go bott
vcodi=strzero(val(codi)+1,5)
repl codi with vcodi, .....
dbcommit()
unlock
endif
endif
Espero ter ajudado. Abraço.
Re: Rotina de codigo automático
Enviado: 02 Dez 2008 15:21
por Josmar dos Santos
Blz..Ademir
Obrigado pela sua atenção !
Pode deixar, vou testar o seu teste !
:)Pos
Re: Rotina de codigo automático
Enviado: 02 Dez 2008 15:48
por asimoes
Olá,
Se não me engano eu peguei este exemplo aqui no forum.
Eu uso e funciona!
[]´s
Código: Selecionar todos
SELECT C0001
IF lAdicionar
cCodigo:=STRZERO(PsqControle( DBF() ),2)
DbAppend()
C0001->Cod:=cCodigo
ELSE
Rec_Lock()
ENDIF
C0001->Nome:= cNome
C0001->(DbCommit())
C0001->(DbUnlock())
FUNCTION PsqControle( cDataBase )
// Inicializa controle com um numero diferente do total de registros
//Exemplo:
//CLIENTES->IDCLIENTE := PsqControle( DBF() )
//APPEND BLANK
//...
//COMMIT
//...
DEFAULT cDirSys TO ""
nControle := IIF( RecCount()=0, 1, RecCount()+(RecCount()/2) )
// Guarda a área atual do .DBf a ser controlado
OldArea := Select()
IF !File(cDirSys+"CONTROLE.DBF")
// Cria a estrutura do controlador caso ainda não exista
aStru_DBF := { ;
{ "DATABASE" , "C",12, 0 } , ; // Guarda o nome do DBF/ALIAS
{ "CONTADOR" , "N", 9, 0 } } // Armazena o contador
DBCREATE( cDirSys+"CONTROLE", aStru_DBF )
ENDIF
IF Select("CONTROLE") == 0 // Se ainda não estiver aberto, abre...
USE &cDirSys.CONTROLE NEW
ELSE
DbSelectar("CONTROLE") // Se ja estiver aberto SELECIONA
ENDIF
// Verifica a existencia da chave( que pode ser também uma palavra )
LOCATE FOR UPPER(CONTROLE->DataBase) = UPPER(cDataBase)
IF Found()
// Encontrando incrementa o contador
//nControle := controle->contador + 1
RLOCK() // Usado no caso de rede
nControle := CONTROLE->Contador + 1
CONTROLE->Contador := nControle
CONTROLE->(DbCommit())
CONTROLE->(DbUnlock())
ELSE
// Caso a chave ainda não exista será criada
APPEND BLANK
CONTROLE->DataBase := cDataBase
CONTROLE->Contador := nControle
CONTROLE->(DbCommit())
ENDIF
// Volta a área antiga
SELECT (OldArea)
// Retorna o numero de controle
RETURN nControle
Re: Rotina de codigo automático
Enviado: 02 Dez 2008 16:33
por SandroBelarmino
No exemplo do Ademir falta um dbappend(), o codigo ficaria assim:
Código: Selecionar todos
if acao=´Inclusao´
if arqlock(5)
go bott
vcodi=strzero(val(codi)+1,5)
dbappend() // colocar esse comando, senao vai gravar o novo codigo por cima do ultimo existente.
repl codi with vcodi, .....
dbcommit()
unlock
endif
endif
Abraços.
Re: Rotina de codigo automático
Enviado: 02 Dez 2008 21:08
por Josmar dos Santos
Ola asimoes, essa rotina que vc descreveu, serve também para campo caracter ou somente campo numérico ??
:)Pos
Re: Rotina de codigo automático
Enviado: 03 Dez 2008 11:55
por gvc
O bloqueio do arquivo ou último registro costuma dar problemas. Veja o post referido acima.
Re: Rotina de codigo automático
Enviado: 03 Dez 2008 13:11
por asimoes
Olá Josmar,
Ola asimoes, essa rotina que vc descreveu, serve também para campo caracter ou somente campo numérico ??
Sim, tanto campo númerico como caracter.
O Retorno da função PsqControle é do tipo númerico.
Caso queira gravar em um campo caracter tem que converter usando funções do tipo strzero ou str
O uso da função PsqControle é interessante quando a casos em que é feito um pack na tabela de sistema que tenho um campo código, como a tabela controle é que fornece o número não tem como gear um código com numero 1 ou 001 por exemplo.
[]´s
Re: Rotina de codigo automático
Enviado: 03 Dez 2008 16:00
por Ademir
Boa tarde amigos !
Em primeiro lugar agradeço ao Sandro por corrgir meu exemplo. Com relação a funcionalidade de se obter o proximo codigo /numero bloqueando o arquivo, posso dizer que funciona perfeitamente, pois o arquivo apenas ficara bloqueado por nao mais que 5 segundos e esse tempo é muito mais que suficiente para isso. Agora, se esse arquivo for "limpo" periodicamente, seria interessante optar por obter o proximo codigo/numero utilizando um arquivo de controle de sequencias, pois num arquivo limpo, o proximo numero seria o 1 que poderia já existir anteriormente.
Re: Rotina de codigo automático
Enviado: 03 Dez 2008 22:34
por asimoes
Ademir,
O problema que você mencionou está resolvido no exemplo que eu postei.
Com a função PsqControle()
Re: Rotina de codigo automático
Enviado: 08 Ago 2010 13:00
por Josmar dos Santos
Ola to levantando a lebre sobre esse assunto de novo ! Essa rotina q estou passando é do miro3, faz parte de um sistema bem antigo no qual estou tentando melhorá-lo. Estou tentando introduzir a função PsqControle() para colocar um número sequêncial. É claro q há varias alternativas, mas escolhi essa. Andei fazendo algumas tentativas de se colocar o mesmo, mas houve dois problemas de cara:
Prime: O número aparece, mas so de eu entrar no cadastro e ficar dando <ESC> e saindo, o número fica pulando sendo q não foi registrado nada!
Pergunto: Qual seria o local ideal para se chamar essa função para não ocorrer tais erros ?
Segundo: Ao tentar registrar o codigo, após confirmar as informações gera esse erro
E também o codigo gerado após a confirmação mesmo dando esse erro não registra o codigo no campo cod_cli
Código: Selecionar todos
LOCAL CONTAR
RE_GISTROS := {}
MENSAGEM( "Aguarde abertura de arquivos" )
SELE 1
IF !USEREDE( "CLIENTES", .F., 10 )
BEEP()
MENSAGEM( "O arquivo CLIENTES n„o est dispon¡vel", 3 )
RETURN
ELSE
SET INDEX TO CLIEN001, CLIEN002
ENDIF
IF !REDE_CONTROLE()
BEEP()
MENSAGEM( "O arquivo OFIC.RED n„o est dispon¡vel", 3 )
RETURN
ENDIF
SELE CLIENTES
COR( "MENU" )
@ LIN_MENU, 00
@ LIN_MENU, 01 SAY "Cadastro ³ CLIENTES"
DU_PLICIDADE := .F.; MOSTRA_RESULTADO := .F.
PRIVATE COD_CLI, NOM_CLI, DAT_CLI
WHILE .T.
MENSAGEM( "Tecle <ESC> para retornar" )
IF !(DU_PLICIDADE )
CARREG01( INCLUSAO )
ELSE
MOSTRA_RESULTADO := .T.
ENDIF
IF CARGET01( INCLUSAO )=.F.
EXIT
ENDIF
IF PERG( "Confirma as informa‡”es ?" ) = "N"
DU_PLICIDADE := .T.
LOOP
ENDIF
DU_PLICIDADE := .F.
MOSTRA_RESULTADO := .F.
IF !ADIREG( 0 )
DU_PLICIDADE := .T.
MENSAGEM( "Inclus„o n„o foi bem sucedida", 3 )
LOOP
ENDIF
SALVAR01()
COMMIT
UNLOCK
ENDDO
SELE 100
FOR CONTAR := 1 TO LEN( RE_GISTROS )
GOTO RE_GISTROS[ CONTAR ]
IF REGLOCK( 2 )
DELE
UNLOCK
ENDIF
NEXT
RESTSCREEN( LIN_MENU + 1, 00, 23, 79, TELA_PRI )
FUNCTION CARREG01( TIPO_ACAO )
IF TIPO_ACAO = INCLUSAO
GOTO BOTT
SKIP
ENDIF
COD_CLI := CLIENTES->COD_CLI
NOM_CLI := CLIENTES->NOM_CLI
DAT_CLI := CLIENTES->DAT_CLI
DAT_CLI := DATE()
// -> Codigo automatico
IF TIPO_ACAO = INCLUSAO
SET ORDER TO 1
COD_CLI:=PsqControle("CLIENTES")
ENDIF
FUNCTION CARGET01( TIPO_ACAO )
IF TIPO_ACAO != MOSTRA_PAG_1
AL_TERAR := .F.
ENDIF
JANELA( 3, 9, 12, 68, "CLIENTES" )
COR( "CERCADURAS" )
@ 4, 10 TO 11, 67 DOUBL
COR( "GETS" )
@ 4, 29 SAY "CADASTRO DE CLIENTES"
@ 7, 12 SAY "CODIGO:"
@ 7,21 SAY COD_CLI PICTURE "@!"
@ 7, 29 SAY "DATA:" GET DAT_CLI
@ 9, 12 SAY "NOME..:" GET NOM_CLI PICTURE "@!"
IF TIPO_ACAO = MOSTRA_PAG_1
CLEAR GETS
RETURN .F.
ENDIF
IF TIPO_ACAO = CONSULTA .OR. TIPO_ACAO = EXCLUSAO
CLEAR GETS
IF TIPO_ACAO = EXCLUSAO
RETURN .T.
ENDIF
MENSAGEM( "Tecle algo para continuar" )
IF INKEY( 0 ) = T_ESC
RETURN .F.
ENDIF
ELSE
CURSOR( LIGA )
READ
CURSOR( DESLIGA )
IF LASTKEY() = T_ESC
RETURN .F.
ENDIF
ENDIF
RETURN .T.
FUNCTION SALVAR01
CLIENTES->COD_CLI := COD_CLI
CLIENTES->NOM_CLI := NOM_CLI
CLIENTES->DAT_CLI := DAT_CLI
FUNCTION PsqControle( database )
nControle := iif( recco()=0, 1, recco()+(recco()/4) )
OldArea := Select()
if !file( "CONTROLE.DBF" )
ESTRU_DBF := { { "DATABASE" , "C",12, 0 } , ;
{ "CONTADOR" , "N", 7, 0 } } // Controle de FINANCEIRO
DBCREATE( "CONTROLE", ESTRU_DBF )
endif
If Select("CONTROLE") == 0
USE controle NEW
Else
DbSelectar("CONTROLE")
EndIf
LOCATE FOR UPPER(controle->database) = UPPER(database)
if found()
nControle := controle->contador + 1
RLOCK()
controle->contador := nControle
COMMIT
else
APPEND BLANK
controle->database := database
controle->contador := nControle
COMMIT
endif
SELE (OldArea)
RETURN nControle
sem mais
Josmar
:%
Re: Rotina de codigo automático
Enviado: 08 Ago 2010 19:22
por rochinha
Amiguinhos,
Salvo quando utilizamos inclusao de 1 para N, exemplo pedido de vendas somente neste caso necessitamos de um codigo de vinculo, o que podemos chamar de codigo temporario ou orcamento.
E porque neste caso voce cria o código temporario? é necessário para que os itens e parcelamentos sendo inclusos fiquem ligados a tabela pai e no momento da efetivação ou gravação, é pesquisado o codigo sequencial final e aplicado a tabela pai e aos filhos.
No caso de uso de codificação em cadastros, ainda mais quando se trata de tratamento de tabelas em rede é praxe assinalar o código final na conclusão da rotina.
Código: Selecionar todos
...
// FLAGeia o procedimento usando uma variavel
local lAppend := "INCLUSAO"
// abre tabelas
// cria tela
// Coloca os campos/gets
// le os dados/read
// pergunta se confirma
// seleciona a tabela alvo
// critica a operacao seguinte
if lAppend = "INCLUSAO"
M->CODIGO := psqControle( "TABELA" )
dbAppend()
else
dbRLock()
endif
// salva os registros na tabela
// salva o cache/COMMIT e libera registro
...
Veja um trecho de código no qual a tecnica se aplica:
Código: Selecionar todos
STATIC FUNCTION CADASTRA( lAppend )
local lSave := .f. // Nunca salva
local nOldRec := RecNo()
lAppend := iif( lAppend=nil, "NOVO", lAppend )
if lAppend = "NOVO"
// Vai ao registro fantasma
GOTO BOTTOM
SKIP
endif
SELE CUSTOMER
// deéndendo do conteudo de lAppend pucha registro vazio ou com dados
CR_CUSTOMER( lAppend )
CLEAR SCREEN
@ BOX ...
@ 1, 1 SAY "FIRST:"
@ 3, 1 SAY "LAST:"
@ 5, 1 SAY "STREET:"
@ 7, 1 SAY "CITY:"
@ 9, 1 SAY "STATE:"
@ 11, 1 SAY "ZIP:"
@ 13, 1 SAY "HIREDATE:"
@ 15, 1 SAY "MARRIED:"
@ 17, 1 SAY "AGE:"
@ 19, 1 SAY "SALARY:"
@ 1, 1 SAY "NOTES:"
@ 1, 15 GET VAR M->FIRST
@ 3, 15 GET VAR M->LAST
@ 5, 15 GET VAR M->STREET
@ 7, 15 GET VAR M->CITY
@ 9, 15 GET VAR M->STATE
@ 11, 15 GET VAR M->ZIP
@ 13, 15 GET VAR M->HIREDATE
@ 17, 15 GET VAR M->AGE
@ 19, 15 GET VAR M->SALARY
@ 1, 15 GET VAR M->NOTES
IF SuaFuncaoDePergunta( "Deseja salvar?" ) = "S"
lSave := .t.
ENDIF
if lSave
SELE CUSTOMER
if lAppend ="NOVO"
// Neste caso o praze seria usar o nome da propria tabela alvo assim não haveria necessidade de lembrar
// o nome de cada variavel
M->NUMBER := Psqcontrole( dbf() )
APPEND BLANK
else
RLOCK()
endif
SV_CUSTOMER()
COMMIT
endif
return nil
FUNCTION CR_CUSTOMER( TIPO_ACAO )
//
// -> Carrega variaveis para entrada ou altercao de dados
IF TIPO_ACAO = "NOVO"
GOTO BOTT
SKIP
ENDIF
M->NUMBER := CUSTOMER->NUMBER
M->FIRST := CUSTOMER->FIRST
M->LAST := CUSTOMER->LAST
M->STREET := CUSTOMER->STREET
M->CITY := CUSTOMER->CITY
M->STATE := CUSTOMER->STATE
M->ZIP := CUSTOMER->ZIP
M->HIREDATE := CUSTOMER->HIREDATE
M->AGE := CUSTOMER->AGE
M->SALARY := CUSTOMER->SALARY
M->NOTES := CUSTOMER->NOTES
IF TIPO_ACAO = "NOVO"
//
// -> Deficao de valores constantes
ENDIF
RETURN .T.
FUNCTION SV_CUSTOMER
//
// -> Salva o conteudo das variaveis de entrada no arquivo
CUSTOMER->NUMBER := M->NUMBER
CUSTOMER->FIRST := M->FIRST
CUSTOMER->LAST := M->LAST
CUSTOMER->STREET := M->STREET
CUSTOMER->CITY := M->CITY
CUSTOMER->STATE := M->STATE
CUSTOMER->ZIP := M->ZIP
CUSTOMER->HIREDATE := M->HIREDATE
CUSTOMER->AGE := M->AGE
CUSTOMER->SALARY := M->SALARY
CUSTOMER->NOTES := M->NOTES
COMMIT
RETURN .T.
//---------------------------------------------------------------------------//
STATIC FUNCTION FUN( oLbx )
RETURN NIL