Olá pessoal…
Em algumas migrações temos o problema de alguns campos serem sobrepostos (como o X3_FOLDER), para isso, foi criado uma rotina que sobrepõe o conteúdo da SX3 através de um arquivo dbf / dtc.
Ao executar a rotina, é mostrado uma tela de parâmetros, onde é possível definir o arquivo de origem, o alias de qual tabela (se for informado *, serão processados todas as tabelas), e os campos do Dicionário que serão sobrepostos.
E após finalizar, além de gerar um arquivo de log dentro da pasta \x_log_sx3\ (dentro da Protheus Data), é mostrado uma tela com as alterações realizadas (abaixo um exemplo da SA2).
Abaixo o código da função desenvolvida (também foi desenvolvida a user funcion zRepAll, que processa todas as tabelas em bloco).
//Bibliotecas #Include "Protheus.ch" /*/{Protheus.doc} zRepSX3 Função que dá replace em campos da SX3, conforme arquivo de origem @author Atilio @since 11/11/2016 @version 1.0 @type function @example U_zRepSX3("\x_pasta\sx3_orig.dbf", "SA1", "X3_RELACAO;X3_FOLDER") /*/ User Function zRepSX3(cArquiPar, cAliasPar, cCamposPar) Local aArea := GetArea() Default cArquiPar := "" Default cAliasPar := "" Default cCamposPar := "" Private lAuto := .F. Private cPerg := "X_ZREPSX3" Private cArquiAux := "" Private cAliasAux := "" Private cCamposAux := "" //Cria / Atualiza o Grupo de Perguntas fValidPerg() //Se veio dados do parâmetro, será de forma automática If !Empty(cArquiPar) .And. !Empty(cAliasPar) .And. !Empty(cCamposPar) cArquiAux := cArquiPar cAliasAux := cAliasPar cCamposAux := cCamposPar lAuto := .T. Processa({|| fAtualiza()}, 'Atualizando') Else //Se a Pergunta for Confirmada, chama a atualização If Pergunte(cPerg, .T.) cArquiAux := MV_PAR01 cAliasAux := MV_PAR02 cCamposAux := MV_PAR03 //Se estiver algum campo em branco, aborta If Empty(cArquiAux) .Or. Empty(cAliasAux) .Or. Empty(cCamposAux) MsgAlert("Existe(m) parâmetro(s) em branco.", "Atenção") Else Processa({|| fAtualiza()}, 'Atualizando') EndIf EndIf EndIf RestArea(aArea) Return /*---------------------------------------------------------------------* | Func: fValidPerg | | Autor: Daniel Atilio | | Data: 11/11/2016 | | Desc: Função para criar o grupo de perguntas | *---------------------------------------------------------------------*/ Static Function fAtualiza() Local aArea := GetArea() Local aAreaX3 := SX3->(GetArea()) Local aStruX3 := SX3->(DbStruct()) Local aCampVer := StrTokArr(Alltrim(cCamposAux), ';') Local aCampos := {} Local nAtual := 0 Local cAliasTmp := "SX3_TMP" Local cArqTmp := "" Local cIndTmp := "" Local cLogAux := "" Local xContOld := Nil Local xContNew := Nil Local nTotal := 0 Local cDirLog := "\x_log_sx3\" //Verifica na DbStruct, se esses campos realmente existem For nAtual := 1 To Len(aCampVer) //Se encontrou o campo no Dicionário If aScan(aStruX3, {|x| Alltrim(x[1]) == Alltrim(aCampVer[nAtual])}) > 0 aAdd(aCampos, aCampVer[nAtual]) EndIf Next //Caso não existam, retorna If Len(aCampVer) == 0 MsgAlert("Campos da SX3 não encontrados!", "Atenção") Return EndIf //Se o arquivo não existir, retorna If !File(cArquiAux) MsgAlert("Arquivo de dados não encontrado!", "Atenção") Return EndIf //Abre o arquivo como uma temporária, cria um índice por campo e filtra a tabela DbUseArea(.T., "DBFCDX", cArquiAux, cAliasTmp, .T., .F.) cArqTmp := CriaTrab(Nil, .F.) cIndTmp := "X3_CAMPO" IndRegua(cAliasTmp, cArqTmp, cIndTmp, , , "Criando Indice temporario...") If cAliasAux != '*' (cAliasTmp)->(DbSetFilter({|| X3_ARQUIVO == cAliasAux }, "X3_ARQUIVO == '"+cAliasAux+"'")) EndIf //Filtra o Dicionário DbSelectArea('SX3') If cAliasAux != '*' SX3->(DbSetFilter({|| X3_ARQUIVO == cAliasAux }, "X3_ARQUIVO == '"+cAliasAux+"'")) EndIf //Inicia controle de transação Begin Transaction //Seta a Regua SX3->(DbGoTop()) Count To nTotal ProcRegua(nTotal) //Percorre o Dicionário enquanto for essa tabela SX3->(DbGoTop()) While ! SX3->(EoF()) IncProc("Analisando "+Alltrim(SX3->X3_CAMPO)+"...") //Se conseguir posicionar no campo na temporária If (cAliasTmp)->(DbSeek(SX3->X3_CAMPO)) RecLock('SX3', .F.) //Percorre os campos For nAtual := 1 To Len(aCampos) xContOld := &("SX3->"+aCampos[nAtual]) xContNew := &(cAliasTmp+"->"+aCampos[nAtual]) //Somente se o conteúdo novo não estiver em branco If !Empty(Alltrim(cValToChar(xContNew))) //Somente se o conteúdo antigo for diferente do novo If xContOld != xContNew //Atualiza variável de log cLogAux += "Campo "+SX3->X3_CAMPO+" - "+aCampos[nAtual]+", '"+; Alltrim(cValToChar(xContOld))+"' -> '"+Alltrim(cValToChar(xContNew))+"'; "+; Chr(13)+Chr(10) //Se for tipo Numérico If ValType(xContNew) == 'N' xContNew := cValToChar(xContNew) //Se for tipo Data ElseIf ValType(xContNew) == 'D' xContNew := 'sToD("'+dToS(xContNew)+'")' //Senão Else //Se tiver Aspas no Conteúdo, utilizará apóstrofo If '"' $ xContNew xContNew := "'"+xContNew+"'" Else xContNew := '"'+xContNew+'"' EndIf EndIf //Sobrepõe os campos da SX3 &("SX3->"+aCampos[nAtual]+" := "+xContNew) EndIf EndIf Next SX3->(MsUnlock()) EndIf SX3->(DbSkip()) EndDo //Se tiver mensagem, teve atualização If !Empty(cLogAux) cLogAux := "A tabela '"+cAliasAux+"' teve as seguintes atualizações: "+Char(13)+Chr(10)+Char(13)+Chr(10)+; cLogAux //Mostra a mensagem If !lAuto Aviso("Atenção", cLogAux, , 3) EndIf //Caso não exista o diretório de Log, cria If !ExistDir(cDirLog) MakeDir(cDirLog) EndIf //Gera o Log If cAliasAux == '*' MemoWrite(cDirLog+"TUDO_sim_"+dToS(Date())+"_"+StrTran(Time(), ':', '-')+".log", cLogAux) Else MemoWrite(cDirLog+cAliasAux+"_sim_"+dToS(Date())+"_"+StrTran(Time(), ':', '-')+".log", cLogAux) EndIf Else cLogAux := "A tabela '"+cAliasAux+"' não teve atualizações!" If cAliasAux == '*' MemoWrite(cDirLog+cAliasAux+"_nao_"+dToS(Date())+"_"+StrTran(Time(), ':', '-')+".log", cLogAux) Else MemoWrite(cDirLog+"TUDO_nao_"+dToS(Date())+"_"+StrTran(Time(), ':', '-')+".log", cLogAux) EndIf EndIf //Fecha a temporária e limpa o filtro do Dicionário (cAliasTmp)->(DbCloseArea()) SX3->(DbClearFilter()) //Finaliza a Transação End Transaction RestArea(aAreaX3) RestArea(aArea) Return /*---------------------------------------------------------------------* | Func: fValidPerg | | Autor: Daniel Atilio | | Data: 11/11/2016 | | Desc: Função para criar o grupo de perguntas | *---------------------------------------------------------------------*/ Static Function fValidPerg() //( cGrupo, cOrdem, cPergunt, cPergSpa, cPergEng, cVar, cTipo, nTamanho, nDecimal, nPreSel, cGSC, cValid, cF3, cGrpSXG, cPyme, cVar01, cDef01, cDefSpa1, cDefEng1, cCnt01, cDef02, cDefSpa2, cDefEng2, cDef03, cDefSpa3, cDefEng3, cDef04, cDefSpa4, cDefEng4, cDef05, cDefSpa5, cDefEng5, aHelpPor, aHelpEng, aHelpSpa, cHelp) PutSx1( cPerg, "01", "Arquivo Origem?", "", "", "mv_ch0", "C", 60, 0, 0, "F", "", "", "", "", "mv_par01", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", {}, {}, {}, "") PutSx1( cPerg, "02", "Tabela (Alias)?", "", "", "mv_ch1", "C", 3, 0, 0, "G", "NaoVazio()", "SX2PAD", "", "", "mv_par02", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", {}, {}, {}, "") PutSx1( cPerg, "03", "Campos SX3 (separado por ;)?", "", "", "mv_ch2", "C", 60, 0, 0, "G", "NaoVazio()", "", "", "", "mv_par03", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", {}, {}, {}, "") Return /*/{Protheus.doc} zRepAll Função que dá um replace de todas as tabelas @author Atilio @since 11/11/2016 @version 1.0 @type function @example u_zRepAll() /*/ User Function zRepAll() Local aArea := GetArea() Local cArqOrig := "\x_p11\sx3_p11.dtc" Local cCampos := "X3_FOLDER" u_zRepSX3(cArqOrig, "*", cCampos) RestArea(aArea) Return
Bom pessoal, por hoje é só.
Abraços e até a próxima.