Olá pessoal…
Se você tem algum importador de Documentos de Entrada ou Pré Nota, imagine o cenário que o usuário importou mais de 100 documentos, mas subiram com algum erro, e ele precisa excluir todos os documentos e re-importar, como fazer para solucionar isso? E se tivesse uma rotina que excluísse vários documentos de entrada de uma só vez?
Foi criado uma funcionalidade com 3 parâmetros, o código do fornecedor, a loja e a data de digitação. Através desses 3, é feito uma consulta SQL na base, encontrado todos os documentos de entrada, e eles são excluídos através de rotina automática (ExecAuto), e se por acaso ainda exista Pré-Nota, elas também são excluídas.
Abaixo o código fonte desenvolvido.
//Bibliotecas #Include "Protheus.ch" #Include "TopConn.ch" /*/{Protheus.doc} zDelDoc Função para excluir vários documentos de entrada ao mesmo tempo @author Atilio @since 23/02/2018 @version 1.0 @type function /*/ User Function zDelDoc() Local aArea := GetArea() Local cPerg := "X_PTCOMM07" Local dUltFec := GetMV('MV_ULMES') Private cFornec := "" Private cLoja := "" Private dDataAux := sToD("") //Cria a pergunta fValidPerg(cPerg) //Se a pergunta for confirmada If Pergunte(cPerg, .T.) cFornec := MV_PAR01 cLoja := MV_PAR02 dDataAux := MV_PAR03 //Somente se os parâmetros estiverem preenchidos If ! Empty(cFornec) .And. ! Empty(cLoja) .And. ! Empty(dDataAux) //Se a data do parâmetro for menor que o último fechamento, não permite excluir If dDataAux < dUltFec MsgStop("Data inválida, fechamento do estoque em "+dToC(dUltFec), "Atenção") Else Processa({|| fProcDel()}, "Excluindo Docs de Entrada...") EndIf EndIf EndIf RestArea(aArea) Return Static Function fValidPerg(cPerg) u_zPutSX1(cPerg, "01", "Fornecedor?", "MV_PAR01", "MV_CH0", "C", TamSX3('A2_COD')[01], 0, "G", /*cValid*/, "SA2", /*cPicture*/, /*cDef01*/, /*cDef02*/, /*cDef03*/, /*cDef04*/, /*cDef05*/, "Informe o código do fornecedor") u_zPutSX1(cPerg, "02", "Loja?", "MV_PAR02", "MV_CH1", "C", TamSX3('A2_LOJA')[01], 0, "G", /*cValid*/, /*cF3*/, /*cPicture*/, /*cDef01*/, /*cDef02*/, /*cDef03*/, /*cDef04*/, /*cDef05*/, "Informe a loja do fornecedor") u_zPutSX1(cPerg, "03", "Data de Digitação?", "MV_PAR03", "MV_CH2", "D", TamSX3('F1_DTDIGIT')[01], 0, "G", /*cValid*/, /*cF3*/, /*cPicture*/, /*cDef01*/, /*cDef02*/, /*cDef03*/, /*cDef04*/, /*cDef05*/, "Informe a data de digitação a ser processada") Return Static Function fProcDel() Local cQrySF1 := "" Local nTotal := 0 Local nAtual := 0 Local cDocs := "" Local lErro := .F. Local aLinha := {} Local aCabSF1 := {} Local aDadSD1 := {} Local nRecBkp := 0 Local cDocBkp := "" Local cKeyBkp := "" Local cError := "" Private lMsErroAuto := .F. DbSelectArea('SF1') SF1->(DbSetOrder(1)) // F1_FILIAL+F1_DOC+F1_SERIE+F1_FORNECE+F1_LOJA+F1_TIPO SF1->(DbGoTop()) DbSelectArea('SD1') SD1->(DbSetOrder(1)) // D1_FILIAL+D1_DOC+D1_SERIE+D1_FORNECE+D1_LOJA+D1_COD+D1_ITEM SD1->(DbGoTop()) DbSelectArea('SA2') SA2->(DbSetOrder(1)) // A2_FILIAL+A2_COD+A2_LOJA SA2->(DbGoTop()) If SA2->(DbSeek(FWxFilial('SA2') + cFornec + cLoja)) //Pega todos os dados via query cQrySF1 := " SELECT " + CRLF cQrySF1 += " SF1.R_E_C_N_O_ AS F1REC, " + CRLF cQrySF1 += " F1_DOC AS DOCUMENTO, " + CRLF cQrySF1 += " F1_FILIAL+F1_DOC+F1_SERIE+F1_FORNECE+F1_LOJA+F1_TIPO AS CHAVE " + CRLF cQrySF1 += " FROM " + CRLF cQrySF1 += " " + RetSQLName('SF1') + " SF1 " + CRLF cQrySF1 += " WHERE " + CRLF cQrySF1 += " F1_FILIAL = '" + FWxFilial('SF1') + "' " + CRLF cQrySF1 += " AND F1_FORNECE = '" + cFornec + "' " + CRLF cQrySF1 += " AND F1_LOJA = '" + cLoja + "' " + CRLF cQrySF1 += " AND F1_DTDIGIT = '" + dToS(dDataAux) + "' " + CRLF cQrySF1 += " AND SF1.D_E_L_E_T_ = ' ' " + CRLF TCQuery cQrySF1 New Alias "QRY_SF1" //Pega o tamanho total de registros e seta na régua Count To nTotal ProcRegua(nTotal) QRY_SF1->(DbGoTop()) //Se houver dados na Query If ! QRY_SF1->(EoF()) //Enquanto houver dados While ! QRY_SF1->(EoF()) nAtual++ IncProc("Analisando documento " + cValToChar(nAtual) + " de " + cValToChar(nTotal) + "...") //Atualiza a variável cDocs += '- ' + Alltrim(QRY_SF1->DOCUMENTO) + ';' + CRLF QRY_SF1->(DbSkip()) EndDo cDocs := "Fornecedor: " + SA2->A2_COD + ' / ' + SA2->A2_LOJA + ' (' + Alltrim(SA2->A2_NOME) + ')' + CRLF +; 'Terá o(s) seguinte(s) documento(s) excluído(s) - Tanto o Documento de Entrada como a Pré Nota: ' + CRLF + cDocs + CRLF + CRLF + 'Confirma?' //Mostra a pergunta se realmente quer continuar If Aviso("Atenção", cDocs, {"Sim","Nao"}, 3) == 1 ProcRegua(nTotal) nAtual := 0 //Posiciona no topo da query, e percorre os dados QRY_SF1->(DbGoTop()) While ! QRY_SF1->(EoF()) nAtual++ IncProc("Excluindo documento " + cValToChar(nAtual) + " de " + cValToChar(nTotal) + "...") //Armazena o RecNo, e a chave da tabela, e o documento lErro := .F. aCabSF1 := {} aDadSD1 := {} nRecBkp := QRY_SF1->F1REC cDocBkp := QRY_SF1->DOCUMENTO cKeyBkp := QRY_SF1->CHAVE //Posiciona na SF1, monta o cabeçalho do array SF1->(DbGoTop()) If SF1->(DbSeek(cKeyBkp)) aAdd(aCabSF1, {"F1_DOC", SF1->F1_DOC, Nil}) aAdd(aCabSF1, {"F1_SERIE", SF1->F1_SERIE, Nil}) aAdd(aCabSF1, {"F1_FORNECE", SF1->F1_FORNECE, Nil}) aAdd(aCabSF1, {"F1_LOJA", SF1->F1_LOJA, Nil}) aAdd(aCabSF1, {"F1_TIPO", SF1->F1_TIPO, Nil}) aAdd(aCabSF1, {"F1_ESPECIE", SF1->F1_ESPECIE, Nil}) //Posiciona na SD1 SD1->(DbGoTop()) If SD1->(DbSeek(FWxFilial('SD1') + SF1->F1_DOC + SF1->F1_SERIE + SF1->F1_FORNECE + SF1->F1_LOJA)) //Percorre os itens e monta o array de itens While ! SD1->(EoF()) .And.; SD1->D1_DOC == SF1->F1_DOC .And.; SD1->D1_SERIE == SF1->F1_SERIE .And.; SD1->D1_FORNECE == SF1->F1_FORNECE .And.; SD1->D1_LOJA == SF1->F1_LOJA aLinha := {} aAdd(aLinha, {"D1_DOC", SD1->D1_DOC, Nil}) aAdd(aLinha, {"D1_SERIE", SD1->D1_SERIE, Nil}) aAdd(aLinha, {"D1_FORNECE", SD1->D1_FORNECE, Nil}) aAdd(aLinha, {"D1_LOJA", SD1->D1_LOJA, Nil}) aAdd(aLinha, {"D1_TIPO", SD1->D1_TIPO, Nil}) aAdd(aLinha, {"D1_ITEM", SD1->D1_ITEM, Nil}) aAdd(aLinha, {"D1_COD", SD1->D1_COD, Nil}) aAdd(aDadSD1, aClone(aLinha)) SD1->(DbSkip()) EndDo //Ordena pelo número do item aSort(aDadSD1, , , { |x, y| x[6] < y[6] }) EndIf //Começa o controle de transação Begin Transaction //Caso haja Status, é Documento de Entrada If ! Empty(SF1->F1_STATUS) //Chama o Execauto de exclusão de documento de entrada lMsErroAuto := .F. MSExecAuto({|x, y, z| MATA103(x, y, z)}, aCabSF1, aDadSD1, 5) //Se houve erro, mostra o erro, disarma a transação e atualiza a variável If lMsErroAuto MostraErro() DisarmTransaction() lErro := .T. cError += "- Documento '" + cDocBkp + "', não foi possível excluir Documento de Entrada!" + CRLF EndIf EndIf //Caso não haja erro If ! lErro //Posiciona novamente no documento SF1->(DbGoTop()) If SF1->(DbSeek(cKeyBkp)) //Se for o mesmo, verifica se o status está em branco (é uma pré nota) If Empty(SF1->F1_STATUS) //Chama o Execauto de exclusão da pré nota lMsErroAuto := .F. MSExecAuto({|x, y, z| MATA140(x, y, z)}, aCabSF1, aDadSD1, 5) //Se houve erro, mostra o erro, disarma a transação e atualiza a variável If lMsErroAuto MostraErro() DisarmTransaction() lErro := .T. cError += "- Documento '" + cDocBkp + "', não foi possível excluir a Pré Nota de Entrada!" + CRLF EndIf EndIf EndIf EndIf End Transaction Else cError += "- Documento '" + cDocBkp + "' não encontrado!" + CRLF EndIf QRY_SF1->(DbSkip()) EndDo //Caso tenha algum log de erro, mostra ao usuário com todos os docs listados If ! Empty(cError) Aviso("Atenção", "Houveram os seguintes erros na atualização: " + CRLF + cError, {"Ok"}, 3) Else MsgInfo("Processo finalizado!", "Atenção") EndIf EndIf Else MsgStop("Não há dados para esse fornecedor, nessa data de digitação!", "Atenção") EndIf QRY_SF1->(DbCloseArea()) Else MsgStop("Fornecedor não encontrado!", "Atenção") EndIf Return
Bom pessoal, por hoje é só.
Abraços e até a próxima.
Mestre, você é o cara, esta rotina me ajudou e muitoooo, valeww…
Boa tarde Mano Charles.
Muito obrigado pelo comentário jovem.
Um grande abraço.