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.
uma boa é essa: NextNumero(“SZ7″,1,”Z7_NUM”,.F., “000009”)
Opa, ótima dica Jonathan. Obrigado pela contribuição.
A NextNumero, por trás utiliza query SQL Server por trás, até fiz um artigo uma vez demonstrando como acertar a numeração do D3_DOC – https://terminaldeinformacao.com/2020/10/12/como-acertar-a-numeracao-do-d3_doc/
Grande abraço.