Nesse artigo vamos demonstrar uma customização para recriar a SF1 quando não há dados lançados nela.
Infelizmente pessoal, pode ser que existam cenários, ou bugs, principalmente em ambientes customizados ou quando há alguma queda de energia, onde corrompem as informações de alguma tabela.
Ou até mesmo algum “des-posicionamento” de informações.
Já pegamos essa situação em mais de um cliente com a tabela SF1, onde as informações tinham na SD1, mas a SF1 não constava nada lançado para ela.
Como não conhecíamos o cenário da empresa, nem as customizações envolvidas, o que fizemos foi o seguinte:
- Uma rotina que lê a SD1
- Abre uma tela de markbrowse e o usuário seleciona os registros
- É recriado as informações da SF1
- Nisso, o usuário depois de recriar, ele tem que ir na tela de documento de entrada e excluir o registro
- Depois lançar novamente
Isso pessoal, é apenas um paliativo, até vocês investigarem o que houve e corrigirem de fato o problema. No cenário que pegamos, era um ponto de entrada que em certas condições “des-posicionava” a SF1 no momento da gravação (falta de FWGetArea e FWRestArea).
Abaixo o código fonte criado para refazer a SF1:
//Bibliotecas
#Include "Totvs.ch"
#Include "FWMVCDef.ch"
#Include "TopConn.ch"
/*/{Protheus.doc} User Function zRefazSF1
Refaz SF1
@author Daniel Atilio
@since 10/10/2022
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/
User Function zRefazSF1()
Local aArea := FWGetArea()
Local aPergs := {}
Local xPar0 := sToD(cValToChar(Year(Date())) + "0101")
//Adicionando os parametros do ParamBox
aAdd(aPergs, {1, "Considera a partir de", xPar0, "", ".T.", "", ".T.", 80, .T.})
//Se a pergunta for confirma, chama a tela
If ParamBox(aPergs, "Informe os parametros", , , , , , , , , .F., .F.)
fMontaTela()
EndIf
FWRestArea(aArea)
Return
/*/{Protheus.doc} fMontaTela
Monta a tela com a marcação de dados
@author Daniel Atilio
@since 10/10/2022
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/
Static Function fMontaTela()
Local aArea := GetArea()
Local aCampos := {}
Local oTempTable := Nil
Local aColunas := {}
Local cFontPad := 'Tahoma'
Local oFontGrid := TFont():New(cFontPad,,-14)
//Janela e componentes
Private oDlgMark
Private oPanGrid
Private oMarkBrowse
Private cAliasTmp := GetNextAlias()
Private aRotina := MenuDef()
//Tamanho da janela
Private aTamanho := MsAdvSize()
Private nJanLarg := aTamanho[5]
Private nJanAltu := aTamanho[6]
//Adiciona as colunas que serão criadas na temporária
aAdd(aCampos, { 'OK', 'C', 2, 0}) //Flag para marcação
aAdd(aCampos, { 'D1_FILIAL', 'C', TamSX3('D1_FILIAL')[1], 0}) //Filial
aAdd(aCampos, { 'D1_DOC', 'C', TamSX3('D1_DOC')[1], 0}) //Documento
aAdd(aCampos, { 'D1_SERIE', 'C', TamSX3('D1_SERIE')[1], 0}) //Série
aAdd(aCampos, { 'D1_FORNECE', 'C', TamSX3('D1_FORNECE')[1], 0}) //Fornecedor
aAdd(aCampos, { 'D1_LOJA', 'C', TamSX3('D1_LOJA')[1], 0}) //Loja
aAdd(aCampos, { 'D1_DTDIGIT', 'D', TamSX3('D1_DTDIGIT')[1], 0}) //Data Inclusão
aAdd(aCampos, { 'D1_EMISSAO', 'D', TamSX3('D1_EMISSAO')[1], 0}) //Data Emissão
aAdd(aCampos, { 'D1_TIPO', 'C', TamSX3('D1_TIPO')[1], 0}) //Tipo
//Cria a tabela temporária
oTempTable:= FWTemporaryTable():New(cAliasTmp)
oTempTable:SetFields( aCampos )
oTempTable:Create()
//Popula a tabela temporária
Processa({|| fPopula()}, 'Processando...')
//Adiciona as colunas que serão exibidas no FWMarkBrowse
aColunas := fCriaCols()
//Criando a janela
DEFINE MSDIALOG oDlgMark TITLE 'Tela para Marcação de dados - Autumn Code Maker' FROM 000, 000 TO nJanAltu, nJanLarg COLORS 0, 16777215 PIXEL
//Dados
oPanGrid := tPanel():New(001, 001, '', oDlgMark, , , , RGB(000,000,000), RGB(254,254,254), (nJanLarg/2)-1, (nJanAltu/2 - 1))
oMarkBrowse := FWMarkBrowse():New()
oMarkBrowse:SetAlias(cAliasTmp)
oMarkBrowse:SetDescription('NFs nao encontradas - Refazer SF1 baseado na SD1')
oMarkBrowse:DisableFilter()
oMarkBrowse:DisableConfig()
oMarkBrowse:DisableSeek()
oMarkBrowse:DisableSaveConfig()
oMarkBrowse:SetFontBrowse(oFontGrid)
oMarkBrowse:SetFieldMark('OK')
oMarkBrowse:SetTemporary(.T.)
oMarkBrowse:SetColumns(aColunas)
//oMarkBrowse:AllMark()
oMarkBrowse:SetOwner(oPanGrid)
oMarkBrowse:Activate()
ACTIVATE MsDialog oDlgMark CENTERED
//Deleta a temporária e desativa a tela de marcação
oTempTable:Delete()
oMarkBrowse:DeActivate()
RestArea(aArea)
Return
/*/{Protheus.doc} MenuDef
Botões usados no Browse
@author Daniel Atilio
@since 10/10/2022
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/
Static Function MenuDef()
Local aRotina := {}
//Criação das opções
ADD OPTION aRotina TITLE 'Continuar' ACTION 'u_zCOMM21O' OPERATION 2 ACCESS 0
Return aRotina
/*/{Protheus.doc} fPopula
Executa a query SQL e popula essa informação na tabela temporária usada no browse
@author Daniel Atilio
@since 10/10/2022
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/
Static Function fPopula()
Local cQryDados := ''
Local nTotal := 0
Local nAtual := 0
//Monta a consulta
cQryDados += "SELECT " + CRLF
cQryDados += " D1_FILIAL, " + CRLF
cQryDados += " D1_DOC, " + CRLF
cQryDados += " D1_SERIE, " + CRLF
cQryDados += " D1_FORNECE, " + CRLF
cQryDados += " D1_LOJA, " + CRLF
cQryDados += " D1_DTDIGIT, " + CRLF
cQryDados += " D1_EMISSAO, " + CRLF
cQryDados += " D1_TIPO, " + CRLF
cQryDados += " COUNT(SF1.F1_DOC) AS TOTAL " + CRLF
cQryDados += "FROM " + CRLF
cQryDados += " " + RetSQLName("SD1") + " SD1 " + CRLF
cQryDados += " LEFT JOIN " + RetSQLName("SF1") + " SF1 ON ( " + CRLF
cQryDados += " F1_FILIAL = D1_FILIAL " + CRLF
cQryDados += " AND F1_DOC = D1_DOC " + CRLF
cQryDados += " AND F1_SERIE = D1_SERIE " + CRLF
cQryDados += " AND F1_FORNECE = D1_FORNECE " + CRLF
cQryDados += " AND F1_LOJA = D1_LOJA " + CRLF
cQryDados += " AND SF1.D_E_L_E_T_ = ' ' " + CRLF
cQryDados += " ) " + CRLF
cQryDados += "WHERE " + CRLF
cQryDados += " D1_DTDIGIT >= '" + dToS(MV_PAR01) + "' " + CRLF
cQryDados += " AND SD1.D_E_L_E_T_ = ' ' " + CRLF
cQryDados += "GROUP BY " + CRLF
cQryDados += " D1_FILIAL, " + CRLF
cQryDados += " D1_DOC, " + CRLF
cQryDados += " D1_SERIE, " + CRLF
cQryDados += " D1_FORNECE, " + CRLF
cQryDados += " D1_LOJA, " + CRLF
cQryDados += " D1_DTDIGIT, " + CRLF
cQryDados += " D1_EMISSAO, " + CRLF
cQryDados += " D1_TIPO " + CRLF
cQryDados += "HAVING " + CRLF
cQryDados += " COUNT(SF1.F1_DOC) = 0 " + CRLF
cQryDados += "ORDER BY TOTAL DESC" + CRLF
TCQuery cQryDados New Alias 'QRYDADTMP'
TCSetField('QRYDADTMP', 'D1_DTDIGIT', 'D')
TCSetField('QRYDADTMP', 'D1_EMISSAO', 'D')
//Definindo o tamanho da régua
DbSelectArea('QRYDADTMP')
Count to nTotal
ProcRegua(nTotal)
QRYDADTMP->(DbGoTop())
//Enquanto houver registros, adiciona na temporária
While ! QRYDADTMP->(EoF())
nAtual++
IncProc('Analisando registro ' + cValToChar(nAtual) + ' de ' + cValToChar(nTotal) + '...')
RecLock(cAliasTmp, .T.)
(cAliasTmp)->OK := Space(2)
(cAliasTmp)->D1_FILIAL := QRYDADTMP->D1_FILIAL
(cAliasTmp)->D1_DOC := QRYDADTMP->D1_DOC
(cAliasTmp)->D1_SERIE := QRYDADTMP->D1_SERIE
(cAliasTmp)->D1_FORNECE := QRYDADTMP->D1_FORNECE
(cAliasTmp)->D1_LOJA := QRYDADTMP->D1_LOJA
(cAliasTmp)->D1_DTDIGIT := QRYDADTMP->D1_DTDIGIT
(cAliasTmp)->D1_EMISSAO := QRYDADTMP->D1_EMISSAO
(cAliasTmp)->D1_TIPO := QRYDADTMP->D1_TIPO
(cAliasTmp)->(MsUnlock())
QRYDADTMP->(DbSkip())
EndDo
QRYDADTMP->(DbCloseArea())
(cAliasTmp)->(DbGoTop())
Return
/*/{Protheus.doc} fCriaCols
Função que gera as colunas usadas no browse (similar ao antigo aHeader)
@author Daniel Atilio
@since 10/10/2022
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/
Static Function fCriaCols()
Local nAtual := 0
Local aColunas := {}
Local aEstrut := {}
Local oColumn
//Adicionando campos que serão mostrados na tela
//[1] - Campo da Temporaria
//[2] - Titulo
//[3] - Tipo
//[4] - Tamanho
//[5] - Decimais
//[6] - Máscara
aAdd(aEstrut, { 'D1_FILIAL', 'Filial', 'C', TamSX3('D1_FILIAL')[1], 0, ''})
aAdd(aEstrut, { 'D1_DOC', 'Documento', 'C', TamSX3('D1_DOC')[1], 0, ''})
aAdd(aEstrut, { 'D1_SERIE', 'Série', 'C', TamSX3('D1_SERIE')[1], 0, ''})
aAdd(aEstrut, { 'D1_FORNECE', 'Fornecedor', 'C', TamSX3('D1_FORNECE')[1], 0, ''})
aAdd(aEstrut, { 'D1_LOJA', 'Loja', 'C', TamSX3('D1_LOJA')[1], 0, ''})
aAdd(aEstrut, { 'D1_DTDIGIT', 'Data Inclusão', 'D', TamSX3('D1_DTDIGIT')[1], 0, ''})
aAdd(aEstrut, { 'D1_EMISSAO', 'Data Emissão', 'D', TamSX3('D1_EMISSAO')[1], 0, ''})
aAdd(aEstrut, { 'D1_TIPO', 'Tipo', 'C', TamSX3('D1_TIPO')[1], 0, ''})
//Percorrendo todos os campos da estrutura
For nAtual := 1 To Len(aEstrut)
//Cria a coluna
oColumn := FWBrwColumn():New()
oColumn:SetData(&('{|| ' + cAliasTmp + '->' + aEstrut[nAtual][1] +'}'))
oColumn:SetTitle(aEstrut[nAtual][2])
oColumn:SetType(aEstrut[nAtual][3])
oColumn:SetSize(aEstrut[nAtual][4])
oColumn:SetDecimal(aEstrut[nAtual][5])
oColumn:SetPicture(aEstrut[nAtual][6])
//Adiciona a coluna
aAdd(aColunas, oColumn)
Next
Return aColunas
/*/{Protheus.doc} User Function zCOMM21O
Função acionada pelo botão continuar da rotina
@author Daniel Atilio
@since 10/10/2022
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/
User Function zCOMM21O()
Processa({|| fProcessa()}, 'Processando...')
Return
/*/{Protheus.doc} fProcessa
Função que percorre os registros da tela
@author Daniel Atilio
@since 10/10/2022
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/
Static Function fProcessa()
Local aArea := FWGetArea()
Local cMarca := oMarkBrowse:Mark()
Local nAtual := 0
Local nTotal := 0
Local nTotMarc := 0
//Define o tamanho da régua
DbSelectArea(cAliasTmp)
(cAliasTmp)->(DbGoTop())
Count To nTotal
ProcRegua(nTotal)
//Percorrendo os registros
(cAliasTmp)->(DbGoTop())
While ! (cAliasTmp)->(EoF())
nAtual++
IncProc('Analisando registro ' + cValToChar(nAtual) + ' de ' + cValToChar(nTotal) + '...')
//Caso esteja marcado
If oMarkBrowse:IsMark(cMarca)
nTotMarc++
RecLock("SF1", .T.)
SF1->F1_FILIAL := (cAliasTmp)->D1_FILIAL
SF1->F1_DOC := (cAliasTmp)->D1_DOC
SF1->F1_SERIE := (cAliasTmp)->D1_SERIE
SF1->F1_FORNECE := (cAliasTmp)->D1_FORNECE
SF1->F1_LOJA := (cAliasTmp)->D1_LOJA
SF1->F1_DTDIGIT := (cAliasTmp)->D1_DTDIGIT
SF1->F1_EMISSAO := (cAliasTmp)->D1_EMISSAO
SF1->F1_TIPO := (cAliasTmp)->D1_TIPO
SF1->F1_DUPL := (cAliasTmp)->D1_DOC
SF1->F1_ESPECIE := "SPED"
SF1->F1_STATUS := "A"
SF1->F1_ORIGEM := "zRefazSF1"
SF1->(MsUnlock())
EndIf
(cAliasTmp)->(DbSkip())
EndDo
//Mostra a mensagem de término e caso queria fechar a dialog, basta usar o método End()
FWAlertSuccess('Dos [' + cValToChar(nTotal) + '] registros, foram processados [' + cValToChar(nTotMarc) + '] registros', 'Atenção')
oDlgMark:End()
FWRestArea(aArea)
Return
Bom pessoal, por hoje é só.
Abraços e até a próxima.