Controlar numeração de tabelas no Protheus sem ser pelo License ou via Query

Hoje vou mostrar como fazer o controle de numeração de uma tabela, sem usar o License, nem parâmetros e nem direto via MAX em uma query. Controlando via arquivo txt.

Certa vez eu tive a necessidade de construir um controle de numeração, porém sem alterar parâmetros (PutMV e GetMV), sem pegar o último da tabela com a query (usando SELECT MAX) e sem usar o License, pois a numeração da tabela estava meio “zoneada” (e nesse cliente, como reiniciavam o License para fazer o Backup, a numeração sempre se perdia).

Então a ideia é controlar a numeração via arquivo texto (.txt), e esse arquivo ficará dentro de uma pasta na Protheus Data.

No nosso código fonte então, antes da User Function, iremos criar duas variáveis que serão vistas no fonte inteiro, uma com a pasta dentro da Protheus Data, e um com o nome do arquivo:

Static cPasta := "\x_pasta\"
Static cArqFlag := "z25.txt"

Agora, iremos ter uma variável, que quando alguém clicar no incluir / alterar / etc, irá carregar o número do documento:

cDocAtual := Iif(nOpc == 3, fUltDoc(), Z25->Z25_DOCUME)

Notem que, se for a opção de incluir, ele irá chamar a função fUltDoc(), do contrário vai pegar o campo direto do alias.

Ai nessa função fUltDoc, iremos buscar o valor de dentro do TXT, e se tiver, iremos somar 1 no valor, por exemplo, se retornar “00100”, vai ficar “00101”. E ao fazer isso, já iremos atualizar o arquivo txt com a sequência nova.

Static Function fUltDoc()
	Local aArea   := GetArea()
	Local cUltDoc := ""
	Local cQryUlt := ""
	
	//Se a pasta não existir, será criada
	If ! ExistDir(cPasta)
		MakeDir(cPasta)
	EndIf

	//Se o arquivo existir dentro da pasta, pega o conteúdo do arquivo e soma 1 com ele
	If File(cPasta + cArqFlag)
		cUltDoc := Soma1(MemoRead(cPasta + cArqFlag))
		
	//Senão, busca o último documento através do SQL Server
	Else

		cQryUlt := " SELECT " + CRLF
		cQryUlt += "     ISNULL(MAX(Z25_DOCUME), '000000000') AS ULTIMO " + CRLF
		cQryUlt += " FROM  " + CRLF
		cQryUlt += "     " + RetSQLName('Z25') + " Z25 " + CRLF
		cQryUlt += " WHERE " + CRLF
		cQryUlt += "     Z25_FILIAL = '" + FWxFilial('Z25') + "' " + CRLF
		cQryUlt += "     AND Z25.D_E_L_E_T_ = ' ' " + CRLF
		TCQuery cQryUlt New Alias "QRY_ULT"
		
		//Se teve resultado, pega o campo do SQL, e soma 1 com ele
		If ! QRY_ULT->(EoF())
			cUltDoc := Soma1(QRY_ULT->ULTIMO)
		EndIf
		QRY_ULT->(DbCloseArea())
	EndIf
	
	//Agora será gravado no arquivo TXT, o último documento usado
	MemoWrite(cPasta + cArqFlag, cUltDoc)
	
	RestArea(aArea)
Return cUltDoc

Agora só ficou faltando a última parte, que é quando o usuário cancelar a inclusão, e se ela for a atual em uso, nós voltarmos um número no txt. Então depois da validação do TudoOk da sua rotina, iremos fazer algo nesse sentido:

//Se for Inclusão, mas ter sido cancelada
If nOpc == 3 .And. nOpcA == 0
	//Busca o último documento conforme TXT
	cUltDoc := MemoRead(cPasta + cArqFlag)
	
	//Se o Documento Atual, for igual ao do TXT, iremos voltar 1, e atualizar o TXT
	If cDocAtual == cUltDoc
		cUltDoc := Tira1(cUltDoc)
		MemoWrite(cPasta + cArqFlag, cUltDoc)
	EndIf
EndIf

Bom pessoal, por hoje é só.

Abraços e até a próxima.

Dan Atilio (Daniel Atilio)
Especialista em Engenharia de Software pela FIB. Entusiasta de soluções Open Source. E blogueiro nas horas vagas.

2 Responses

  1. Jonathan disse:

    uma boa é essa: NextNumero(“SZ7″,1,”Z7_NUM”,.F., “000009”)

Deixe uma resposta