1. Identificação da Rotina


Nome da Rotina

Importação Glass
ProgramaOFIA538
Módulo ERPOficina (SIGAOFI)
Acesso à RotinaAtualizações/Cadastros Oficina/Importação Glass (OFIA538)
Data da Documentação (Ultima Atualização)

 



2. Descrição Funcional

A rotina Importação GLASS (OFIA538) tem como finalidade facilitar a importação e atualização das peças enviadas pela montadora Scania para o sistema Protheus DMS, a partir de um arquivo GLASS (Global Assortment), disponibilizado pela própria montadora no formato .DAT.

Esse arquivo contém informações sobre peças, peças substituídas e kits de peças.

Durante a execução da rotina, é necessário preencher os parâmetros obrigatórios e opcionais na tela inicial de configuração, para garantir a consistência dos dados antes de prosseguir com o processamento do arquivo.

Após as validações, o sistema interpreta o conteúdo do arquivo GLASS e executa o processamento de inclusão ou atualização das peças, de acordo com as informações oficiais enviadas pela Scania.

Concluída a importação, o sistema executa as ações de pós processamento configuradas, que podem incluir, manter, mover ou apagar o arquivo, e gera logs detalhados com o resultado da operação.

Dessa forma, a rotina OFIA538 auxilia na organização e manutenção do cadastro de peças da Scania dentro do Protheus DMS, tornando o processo mais eficiente e parametrizável, garantindo que o cadastro de peças no Protheus se mantenha atualizado com as informações oficiais

disponibilizadas pela Scania. e substituindo a rotina OFIIA440, que possuía parâmetros fixos e menor desempenho em arquivos de grande volume.





3. Pré-requisitos e Configurações


Para o correto funcionamento da rotina Importação Glass (OFIA538), é necessário garantir pré-condições que asseguram a leitura adequada do arquivo .DAT:

  1. É necessário incluir manualmente a rotina Importação Glass (OFIA538) ao menu do Protheus, permitindo assim o acesso à funcionalidade.
  2. Deve-se possuir um arquivo com a extensão .DAT  contendo as peças enviadas pela montadora Scania, que será utilizado como base para o processo de importação.


#include "Protheus.ch"
#include 'TOPCONN.ch'
#include 'OFIA538.ch'

/*/{Protheus.doc} OFIA538
    GLASS - SCANIA
    @type  Function
    @author Renan Migliaris
    @since 20/08/2025
    /*/
Function OFIA538()
    local aArea := FwGetArea()
    local lRet := .f.
    local lFunc := .t.
    private lPePro := ExistBlock("OF538PRO")
    private lPeFim := ExistBlock("OF538FIM")
    private lSched := FWGetRunSchedule()
    private cOrigem := ""
    private cPerg := "OFIA538"
    private lPEnt := ExistBlock("IA440DPG") //questão da chamada de ponto de entrada
    private lGruNov := (VE9->(FieldPos("VE9_GRUNOV"))>0)
    private cBZB5 := GetNewPar("MV_CADPROD", '')
    private nValor := 0
    private aFilAtu := FWArrFilAtu()
    private aFilAux := FWAllFilial(aFilAtu[3] , aFilAtu[4] , aFilAtu[1] , .f.) //traz todas as filiais aqui
    private oTmpTab := nil
    private cAliasTmp := ''
    default lEnd := .t.
    

    if lSched
        cOrigem := STR0001 //Scheduler
    else
        cOrigem := STR0002 //Menu
    endif

    if !lSched
        while pergunte(cPerg, !lSched)
            if OA538001J_VerificaPerguntePreenchido()
                FWMsgRun(,{|| OA538002J_ProcessaArquivo(@lFUnc), STR0004})
                if lFunc
                    FWAlertSuccess(STR0005, STR0006) //'OFIA538' //'Arquivo Processado Com Sucesso!'
                    lRet := .t.
                else
                    FMX_HELP(STR0005, STR0027) //OFIA538 //'Uma ou mais perguntas obrigatórias não foram preenchidas corretamente! Verifique as informações e tente novamente.'
                    OA538003J_LogaExecucao(cOrigem, STR0008, OA538004J_ParametrosString(STR0009), .t.) //"Erro" //"Erro execução via menu"
                    lRet := .f.
                endif
                Exit
            end
        endDo
    else
        if OA538001J_VerificaPerguntePreenchido()
            OA538002J_ProcessaArquivo(@lFunc)
            lRet := lFunc
        else   
            OA538003J_LogaExecucao(cOrigem, STR0008, OA538004J_ParametrosString(STR0029), .t.) //"Erro" //"Erro execução via scheduler"
            lRet := .f.
        endif
    endif

    if lPeFim .and. lRet
        ExecBlock("OF538FIM", .f., .f.)
    endif
    RestArea(aArea)
Return lRet

/*/{Protheus.doc} OA538001J_VerificaPerguntePreenchido
    Verificação do eprgunte preenchido
    @author Renan Migliaris
    @since 21/08/2025
/*/
Static Function OA538001J_VerificaPerguntePreenchido()
    local lRet := .t.
    local cExt := alltrim(upper(ExtractExt(MV_PAR05)))
    local aErros := {}
    local cMsg := ''
    local oX1Hlp := FwSX1Util():new()
    local aPergs := {}
    local nX := 0
    local lExistDir := .f.
    local nPar06 := 0

    oX1Hlp:AddGroup(cPerg)
    oX1Hlp:SearchGroup()
    aPergs := oX1Hlp:GetGroup(cPerg)

    if Empty(MV_PAR05) .or. (cExt <> '.DAT')
        aadd(aErros, STR0028)
    endif

    if ValType(MV_PAR06) <> "N"
        nPar06 := 0
    else
        nPar06 := MV_PAR06
    endif

    if (nPar06 == 2) .and. (!Empty(MV_PAR07))
        lExistDir := ExistDir(alltrim(MV_PAR07))
        if !lExistDir
            aadd(aErros, aPergs[2][7]:CX1_PERGUNT)
            lRet := .f.
        endif
    endif

    if len(aErros) > 0 
        if !lSched
            for nx := 1 to len(aErros)
                cMsg += alltrim(aErros[nx])
            next
            FMX_HELP(STR0008, STR0022 + alltrim(cMsg)) //"Erro" //"Os seguintes parâmetros não foram preenchidos corretamente: "
        endif
        lRet := .f.
    endif

Return lRet

/*/{Protheus.doc} OA538002J_ProcessaArquivo()
    Realiza o processamento do arquivo .Dat enviado
    @type  Static Function
    @author Renan Migliaris
    @since 21/08/2025
/*/
Static Function OA538002J_ProcessaArquivo(lRet)
    local cFile := alltrim(MV_PAR05)
    local nAcaoArq := MV_PAR06
    local oFile := FwFileReader():new(cFile)
    local cDest := ''
    local cArqOrig := ''
    local lCopy := .f.
    default lRet := .t.
 
    OA538003J_LogaExecucao(cOrigem, STR0012, OA538004J_ParametrosString()) //"Início"
    if (oFile:Open())
        cArqOrig := alltrim(lower(MV_PAR05))
        OA538005J_PreparaVE9()

        OA538006J_ProcessaArquivoGlass(@oFile)

        lRet := .t.
        oFile:Close()
        OA538003J_LogaExecucao(cOrigem, STR0013, STR0014, .t.) //"Sucesso" //"Processado com sucesso"
        Do Case
            Case nAcaoArq == 2
                cDest := alltrim(lower(alltrim(MV_PAR07)+ "\" + SubStr(cFile, Rat("\", cFile) + 1)))
                lCopy := __CopyFile(cArqOrig, alltrim(lower(cDest)))
                if lCopy
                    oFile:erase()
                endIF
            Case nAcaoArq == 3
                oFile:erase()
        EndCase
    else
        lRet := .f.
        OA538003J_LogaExecucao(cOrigem, STR0008, OA538004J_ParametrosString(STR0015), .t.) //Erro //"Não foi possível realizar a abertura do arquivo"
    endif
Return lRet

/*/{Protheus.doc} OA538003J_LogaExecucao()
    Realiza o log da operação. 
    @type  Static Function
    @author Renan Migliaris
    @since 21/08/2025
/*/
Static Function OA538003J_LogaExecucao(cOrigem, cTipo, cMensagem, lHorFin)
    local aData := {}
    local oLogger := DMS_Logger():new()
    default lHorFin := .f.

    
    aadd(adata, {"VQL_AGROUP", "OFIA538"})
    aadd(adata, {"VQL_FILORI", cFilAnt})
    aadd(adata, {"VQL_TIPO", cTipo})
    aadd(adata, {"VQL_MSGLOG", cMensagem})
    aadd(adata, {"VQL_DADOS", cOrigem})
    if lHorFin
        aadd(aData, {"VQL_HORAF", VAL(STRTRAN(SUBSTR( TIME() , 1, 5), ":", "" ))})
        aadd(adata, {"VQL_DATAF", dDataBase})
    endif

    oLogger:LogToTable(aData)
Return

/*/{Protheus.doc} OA538004J_ParametrosString
    Função que vai guardar os parâmetros que foram recebidos pela função para finalidade de log
    Os parâmetros serão guardados no formato json
    @type  Static Function
    @author Renan Migliaris
    @since 22/08/2025
/*/
Static Function OA538004J_ParametrosString(cMsgErro)
    local cParams := ''
    local oParams := JsonObject():new()
    default cMsgErro := ''

    oParams["MV_PAR01"] := MV_PAR01
    oParams["MV_PAR02"] := MV_PAR02
    oParams["MV_PAR03"] := MV_PAR03
    oParams["MV_PAR04"] := MV_PAR04
    oParams["MV_PAR05"] := MV_PAR05
    oParams["MV_PAR06"] := MV_PAR06
    oParams["MV_PAR07"] := MV_PAR07
    if !Empty(cMsgErro)
        oParams["MSG_ERRO"] := cMsgErro
    endif

    cParams := oParams:toJson()

    freeObj(oParams)
Return cParams

/*/{Protheus.doc} OA538005J_PreparaVE9
    Função que irá realizar a preparação da VE9 para uma nova importação
    @type  Static Function
    @author Renan Migliaris
    @since 25/08/2025    
/*/
Static Function OA538005J_PreparaVE9()
    local oStatement := FWPreparedStatement():New()
    local cQuery := ''
    local cFinalQuery := ''
    local cVeFilial := ''
    DbSelectArea("VE9")
    cVeFilial := xFilial('VE9')
    
    Do Case
        Case Empty(cVeFilial)
            //truncate não vai passar linha a linha deletando o que vai gerar mais performance quando apagar a VE9 
            //tabela será trucanda em casos que a VE9 seja compartilhada
            cQuery := " TRUNCATE TABLE " + RetSQLName('VE9')
            oStatement:SetQuery(cQuery)
        Otherwise
            cQuery := " DELETE FROM " +RetSQLName("VE9")
            cQuery += " WHERE VE9_FILIAL = ? "
            oStatement:SetQuery(cQuery)
            oStatement:SetString(1, cVeFilial)
    EndCase
    
    cFinalQuery := oStatement:GetFixQuery()

    if TCSqlExec(cFinalQuery) < 0
        OA538003J_LogaExecucao(cOrigem, STR0008, OA538004J_ParametrosString(STR0016), .t.) //Erro //"Não foi possível a execução do statement na tabela VE9. Verifique se a tabela está disponível"
        return .f.
    endif 
Return .t.

/*/{Protheus.doc} OA538006J_ProcessaArquivoGlass
    Realiza o processamento do arquivo .dat (glass)
    @type  Static Function
    @author Renan Migliaris
    @since 25/08/2025
/*/
Static Function OA538006J_ProcessaArquivoGlass(oFile)
    local lRet := .t.

    if OA538014J_CriaTabelaTemporaria(@oFile)
        OA538008J_GravaVE9(@oTmpTab)
        OA538007J_VerificaEGravaSb1(@oTmpTab)
        
        If "SB5" $ cBZB5
            OA538009J_VerificaEGravaSb5(@oTmpTab)
        EndIf

        If "SBZ" $ cBZB5
            OA538010J_VerificaEGravaSBZ(@oTmpTab)
        EndIf

        OA538012J_VerificaEGravaVEH(@oTmpTab) //a gravação da VE8 está sendo chamada de dentro da função de gravação da VEH e somente se a gravação da VEH der certo
        oTmpTab:Delete()
    endif 
Return lRet

/*/{Protheus.doc} OA538007J_VerificaEGravaSb1
    Verifica via query quais os registros que não existem na SB1 
    Caso não existirem eu já faço a inclusão deles via bulk
    Mando a tmpTable aqui como parâmetro para acessar seus respectivos métodos do objeto como por exemplo o realname
    @type  Static Function
    @author Renan Migliaris
    @since 27/08/2025
/*/
Static Function OA538007J_VerificaEGravaSb1(oTmpTab)
    local cQuery := ''
    local cRealName := oTmpTab:GetTableNameForQuery()
    local cAlias := ''
    local nX := 0
    local lOk := .t.
    local aFields := {}
    local aFieAux := {}
    local aItem := {}
    local aItAux := {}
    local aFils := OA538015J_VerificaAcessoExclusivo("SB1")
    local oBulkB1 := FwBulk():new(RetSQLName('SB1'), 850)

    aFields := { ;
        {"B1_FILIAL"}, {"B1_COD"}, {"B1_GRUPO"}, {"B1_CODITE"}, {"B1_FABRIC"}, {"B1_DESC"}, ;
        {"B1_UM"}, {"B1_SEGUM"}, {"B1_TIPO"}, {"B1_LOCPAD"}, {"B1_PICM"}, ;
        {"B1_IPI"}, {"B1_PRV1"}, {"B1_CONTA"}, {"B1_CC"}, {"B1_PESO"}, ;
        {"B1_TIPOCQ"}, {"B1_ORIGEM"}, {"B1_CLASFIS"} ;
    }

    if lPePro
        aFieAux := ExecBlock("OF538PRO", .f., .f., {"SB1", .t.})
    endif

    OA538020J_SetaFieldsBulk(@oBulkB1, @aFields, aFieAux)
    
    for nX := 1 to len(aFils)
        cQuery := " SELECT " 
        cQuery += "    T.CODIGO, "
        cQuery += "    T.GRUPO, "
        cQuery += "    T.CODITE, "
        cQuery += "    T.FABRIC, "
        cQuery += "    T.DESCRIC, "
        cQuery += "    T.UM, "
        cQuery += "    T.SEGUM, "
        cQuery += "    T.TIPO, "
        cQuery += "    T.LOCPAD, "
        cQuery += "    T.PICM, "
        cQuery += "    T.IPI, "
        cQuery += "    T.PRV1, "
        cQuery += "    T.CONTA, "
        cQuery += "    T.CENTRO, "
        cQuery += "    T.PESO, "
        cQuery += "    T.TIPOCQ, "
        cQuery += "    T.ORIGEM, "
        cQuery += "    T.CLASFIS "
        cQuery += " FROM " + cRealName + " T "
        cQuery += " WHERE "
        cQuery += "    T.SEGMENTO = '01' "
        cQuery += "    AND NOT EXISTS ( "
        cQuery += "    SELECT 1 FROM " + RetSQLName("SB1") + " SB1 "
        cQuery += "    WHERE SB1.B1_FILIAL = '" + aFils[nX] + "' "
        cQuery += "      AND SB1.B1_GRUPO  = T.GRUPO "
        cQuery += "      AND SB1.B1_CODITE = T.CODITE "
        cQuery += "      AND SB1.D_E_L_E_T_ = ' ' "
        cQuery += ")"

        cAlias := GetNextAlias()

        dbUseArea(.t., "TOPCONN", TcGenQry(,,cQuery), cAlias, .f., .t.)

        while !(cAlias)->(eof())
            aItem := {}
            aadd(aItem, {;
                aFils[nX],;
                (cAlias)->CODIGO,;
                (cAlias)->GRUPO,; 
                (cAlias)->CODITE,;
                (cAlias)->FABRIC,; 
                (cAlias)->DESCRIC,; 
                (cAlias)->UM,; 
                (cAlias)->SEGUM,;
                (cAlias)->TIPO,;
                (cAlias)->LOCPAD,;
                (cAlias)->PICM,;
                (cAlias)->IPI,;
                (cAlias)->PRV1,;
                (cAlias)->CONTA,;
                (cAlias)->CENTRO,;
                (cAlias)->PESO,;
                (cAlias)->TIPOCQ,;
                (cAlias)->ORIGEM,;
                (cAlias)->CLASFIS;
            })

            aItAux := aClone(aItem)

            if lPePro
                aItAux := ExecBlock("OF538PRO", .f., .f., {"SB1", .f. ,aItAux})
            endif

            OA538021J_SetaODadoDoItem(@oBulkB1, aItem, aItAux)

            fwFreeArray(aItem)
            fwFreeArray(aItAux)
            (cAlias)->(DbSkip())
        endDo

        (cAlias)->(dbCloseArea())
        oBulkB1:flush()
    next

    lOk := oBulkB1:Close()
    if .not. lOk
        OA538003J_LogaExecucao(cOrigem, STR0008, OA538004J_ParametrosString(oBulkB1:GetError() + " SB1")) //"ERRO"
    else
        OA538003J_LogaExecucao(cOrigem, STR0013, OA538004J_ParametrosString(STR0017)) //Sucesso //"SB1 SALVA"
    endif
    oBulkB1:Destroy()

    fwFreeArray(aFils)
    fwFreeArray(aFields)
    freeObj(oBulkB1)
Return lOk

/*/{Protheus.doc} OA538008J_GravaVE9
    Aqui já vou fazer o processamento da VE9 em outra thread. 
    Vou receber os parâmetros de filial + empresa 
    o terceiro elemento do array vai ser os dados a serem processados já filtrados pelo 01 
    Ou seja, vou montando o cLinha aqui para realizar o bulk da VE9
    @type Function
    @author Renan Migliaris
    @since 28/08/2025
/*/
Static Function OA538008J_GravaVE9(oTmpTab)
    local aVe9 := {}
    local cQuery := ''
    local lOk := .t.
    local cAlias := ''
    local cRealName := oTmpTab:GetTableNameForQuery()
    local oBulkVE9 := FwBulk():new(RetSQLName('VE9'), 850)
    local cMyFil := xFilial("VE9")
    
    aVE9 := {;
        {"VE9_FILIAL"}, {"VE9_NROSEQ"}, {"VE9_NROSUB"}, {"VE9_GRUITE"},;
        {"VE9_ITEANT"}, {"VE9_ITENOV"}, {"VE9_SEGMEN"}, {"VE9_STAGLA"},;
        {"VE9_APLICA"}, {"VE9_STATUS"}, {"VE9_DATSUB"}, {"VE9_QTDADE"},; 
        {"VE9_QTDSUB"};
    }

    oBulkVE9:setFields(aVe9)

    cQuery := "SELECT "
    cQuery += "    T.SEQVE9, "
    cQuery += "    T.NROSUBVE9, "
    cQuery += "    T.ITENOV, "
    cQuery += "    T.GRUPO, "
    cQuery += "    T.ITEANT, "
    cQuery += "    T.SEGMENTO, "
    cQuery += "    T.STAGLA, "
    cQuery += "    T.APLICA, "
    cQuery += "    T.STATUS, "
    cQuery += "    T.DATSUB, "
    cQuery += "    T.QTDADE, "
    cQuery += "    T.QTDSUB "
    cQuery += "FROM " + cRealName + " T"
    cQuery += " WHERE T.SEGMENTO IN ('01','02','04','06') "
    cAlias := GetNextAlias()
    
    dbUseArea(.t., "TOPCONN", TcGenQry(,,cQuery), cAlias, .f., .t.)

    while !(cAlias)->(eof())
        oBulkVE9:addData({;
            cMyFil,;
            (cAlias)->SEQVE9,;
            (cAlias)->NROSUBVE9,;
            (cAlias)->GRUPO,;
            (cAlias)->ITEANT,;
            (cAlias)->ITENOV,;
            (cAlias)->SEGMENTO,;
            (cAlias)->STAGLA,;
            (cAlias)->APLICA,;
            (cAlias)->STATUS,;
            (cAlias)->DATSUB,;
            (cAlias)->QTDADE,;
            (cAlias)->QTDSUB;
        })
        (cAlias)->(DbSkip())
    end

    oBulkVE9:flush()
    lOk := oBulkVE9:Close()
    oBulkVE9:destroy()

    (cAlias)->(dbCloseArea())
    if lOk
        OA538003J_LogaExecucao(cOrigem, STR0013, OA538004J_ParametrosString(STR0018), .t.)
    else
        OA538003J_LogaExecucao(cOrigem, STR0008, OA538004J_ParametrosString(oBulkVE9:GetError() + " VE9"), .t.)
    endif
    freeObj(oBulkVE9)
Return lOk

/*/{Protheus.doc} OA538009J_VerificaEGravaSb5
    Aqui vou ver quais itens que estão na SB5 e que precisarão ser atualizados. 
    Recebo o array aqui faço um batch no banco de dados e obtenho o retorno do que precisa ser atualizado.
    A busca será feita pelo código do item e deverá considerar todas as filiais
    Primeiro item do aParams vai ser meu array para processamento da braba
    @type  Static Function
    @author Renan Migliaris
    @since 28/08/2025
/*/
Static Function OA538009J_VerificaEGravaSb5(oTmpTab)
    local lOk := .t.
    local aB5Fields := {}
    local nI := 0
    local oBulkB5 := FwBulk():new(RetSQLName("SB5"), 850)
    local cQuery := ''
    local cRealName := oTmpTab:GetTableNameForQuery()
    local cAlias := ''
    local aFils := OA538015J_VerificaAcessoExclusivo("SB5")
    local aFieAux := {}
    local aItAux := {}
    local aItem := {}

    aB5Fields := {;
        {"B5_FILIAL"}, {"B5_COD"}, {"B5_CEME"}, {"B5_UMIND"};
    }

    if lPePro
        aFieAux := ExecBlock("OF538PRO", .f., .f., {"SB5", .t.})
    endif

    OA538020J_SetaFieldsBulk(@obulkB5, @aB5Fields, aFieAux)

    for nI := 1 to len(aFils)
        cQuery := "SELECT T.CODIGO, T.DESCRIC FROM " + cRealName + " T "
        cQuery += " WHERE "
        cQuery += "     T.SEGMENTO = '01' "
        cQuery += "     AND NOT EXISTS ( "
        cQuery += "     SELECT 1 FROM "+ RetSQLName("SB5") + " SB5 "
        cQuery += "     WHERE SB5.B5_FILIAL = '" +aFils[ni]+"'" 
        cQuery += "         AND SB5.B5_COD = T.CODIGO "
        cQuery += "         AND SB5.D_E_L_E_T_ = ' ' "
        cQuery += " )"
        
        cAlias := GetNextAlias()

        dbUseArea(.t., "TOPCONN", TcGenQry(,,cQuery), cAlias, .f., .t.)

        while !(cAlias)->(eof())
            aItem := {}
            aadd(aItem,  {;
                aFils[ni],;
                (cAlias)->CODIGO,;
                (cAlias)->DESCRIC,;
                "1";
            })

            aItAux := aClone(aItem)

            if lPePro
                aItAux := ExecBlock("OF538PRO", .f., .f., {"SB5", .f., aItAux})
            endif
            
            OA538021J_SetaODadoDoItem(@oBulkB5, aItem, aItAux)

            fwFreeArray(aItem)
            fwFreeArray(aItAux)
            (cAlias)->(dbSkip())
        endDo
        (cAlias)->(dbCloseArea())
        oBulkB5:flush()
    next

    lOk := oBulkB5:Close()
    if .not. lOk
        OA538003J_LogaExecucao(cOrigem, STR0008, OA538004J_ParametrosString(oBulkB5:getError() + " SB5")) //erro
    else
        OA538003J_LogaExecucao(cOrigem, STR0013, OA538004J_ParametrosString(STR0019)) //Sucess //"SB5 SALVA"
    endif
    oBulkB5:destroy()

    fwFreeArray(aFils)
    fwFreeArray(aB5Fields)
    freeObj(obulkB5)
return lOk

/*/{Protheus.doc} OA538010J_VerificaEGravaSBZ
    Caso tiver o parâmetro da SBZ vai fazer a gravação dela nessa função aqui
    @type  Static Function
    @author Renan Migliaris
    @since 10/09/2025
/*/
Static Function OA538010J_VerificaEGravaSBZ(oTmpTab)
    local lOk := .t.
    local aBZFields := {}
    local nI := 0
    local oBulkBZ := FwBulk():new(RetSqlName("SBZ"), 850)
    local cQuery := ''
    local cRealName := oTmpTab:GetTableNameForQuery()
    local cAlias := ''
    local aFils := OA538015J_VerificaAcessoExclusivo("SBZ")
    local aFieAux := {}
    local aItem := {}
    local aItAux := {}

    aBZFields := {;
        {"BZ_FILIAL"}, {"BZ_COD"}, {"BZ_LOCPAD"};
    }
    
    if lPePro
        aFieAux := ExecBlock("OF538PRO", .f., .f., {"SBZ", .t.})
    endif

    OA538020J_SetaFieldsBulk(@oBulkBZ, @aBZFields, aFieAux)

    for ni := 1 to len(aFils)
        
        cQuery := " SELECT T.CODIGO, T.LOCPAD FROM " + cRealName + " T "
        cQuery += " WHERE "
        cQuery += "     T.SEGMENTO = '01' "
        cQuery += "     AND NOT EXISTS ( "
        cQuery += "     SELECT 1 FROM "+RetSqlName("SBZ")+" SBZ "
        cQuery += "     WHERE SBZ.BZ_FILIAL = '"+aFils[ni]+"' "
        cQuery += "         AND SBZ.BZ_COD = T.CODIGO "
        cQuery += "         AND SBZ.D_E_L_E_T_ = ' ' "
        cQuery += " )"

        cAlias := GetNextAlias()

        dbUseArea(.t., "TOPCONN", TcGenQry(,,cQuery), cAlias, .f., .t.)

        while !(cAlias)->(eof())
            aItem := {}
            aadd(aItem, {;
                aFilAux[ni],;
                (cAlias)->CODIGO,;
                (cAlias)->LOCPAD;
            })

            aItAux := aClone(aItem)

            if lPePro
                aItAux := ExecBlock("OF538PRO", .f., .f., {"SBZ", .f., aItAux})
            endif

            OA538021J_SetaODadoDoItem(@oBulkBZ, aItem, aItAux)

            fwFreeArray(aItem)
            fwFreeArray(aItAux)
            (cAlias)->(dbSkip())
        endDo

        (cAlias)->(dbCloseArea())
        oBulkBZ:flush()
    next

    lOk := oBulkBZ:Close()
    if .not. lOk
        OA538003J_LogaExecucao(cOrigem, STR0008, OA538004J_ParametrosString(oBulkBZ:getError())) //ERro
    else
        OA538003J_LogaExecucao(cOrigem, STR0013, OA538004J_ParametrosString(STR0020)) //"SUCESSO" //SBZ Salva
    endif
    oBulkBZ:destroy()


    fwFreeArray(aFils)
    fwFreeArray(aBZFields)
    freeObj(oBulkBZ)
Return lOk

/*/{Protheus.doc} OA538011J_MontaItemDeAcordoComOSeguimento
    Vai montar o Itenov de acordo com a linha recebida para a inserção na tabela temporária
    @type  Static Function
    @author Renan Migliaris
    @since 15/09/2025
/*/
Static Function OA538011J_MontaItemDeAcordoComOSeguimento(cLinha)
    Local oRetorno
    Local cSegmento := Left(cLinha, 2)

    oRetorno := JsonObject():new()
    oRetorno["CODIGO"] := UPPER(Subs(cLinha, 3, 7))
    oRetorno["CODITE"] := UPPER(Subs(cLinha, 3, 7))
    oRetorno["DESCRICAO"] := UPPER(Subs(cLinha, 10, 15))
    oRetorno["APLICA"] := ""
    oRetorno["ITEANT"] := UPPER(Subs(cLinha, 3, 7))
    oRetorno["SEGMENTO"] := cSegmento
    oRetorno["ITENOV"] := ""
    oRetorno["CODITE"] := ""
    oRetorno["STAGLA"] := ""
    oRetorno["QTDADE"] := 0
    oRetorno["DATSUB"] := ""
    oRetorno["QTDSUB"] := 0
    oRetorno["STATUS"] := ""
    oRetorno["CODKIT"] := ""

    Do Case
        Case cSegmento == "01" //informação básica do item
            oRetorno["ITENOV"] := UPPER(Subs(cLinha, 3, 7))
            oRetorno["CODITE"] := UPPER(Subs(cLinha, 3, 7))
            oRetorno["STAGLA"] := UPPER(Subs(cLinha, 55, 30))
        
        Case cSegmento == "02"
            oRetorno["APLICA"] := UPPER(Subs(cLinha, 10,35))
            oRetorno["ITENOV"] := UPPER(Subs(cLinha, 3, 7))

        Case cSegmento == "04" //informacoes substituo do item
            oRetorno["ITENOV"] := UPPER(Subs(cLinha, 10, 10))
            oRetorno["QTDADE"] := Val(Subs(cLinha, 20, 7))
            oRetorno["DATSUB"] := dDataBase
            oRetorno["QTDSUB"] := Val(Subs(cLinha, 20, 7))
            oRetorno["STATUS"] := "99"
        
        Case cSegmento == "06" //kits
            oRetorno["CODITE"] := UPPER(Subs(cLinha, 10, 7))
            oRetorno["QTDADE"] := Val(Subs(cLinha, 20, 7))
            oRetorno["CODKIT"] := UPPER(Subs(cLinha, 3, 7))
        
        Case cSegmento == "06" //kits
            oRetorno["CODITE"] := UPPER(Subs(cLinha, 10, 7))
            oRetorno["CODKIT"] := UPPER(Subs(cLinha, 3, 7))
            oRetorno["QTDADE"] := Val(Subs(cLinha, 20, 7))
    EndCase

Return oRetorno

/*/{Protheus.doc} OA538013J_VerificaEGravaVEH
    Vai criar ou atualizar a tabela VEH de acordo com as informações do segmento 06 do arquivo GLASS    
    Tabela cabeçalho de kits
    @type  Static Function
    @author Renan Migliaris
    @since 17/09/2025
/*/
Static Function OA538012J_VerificaEGravaVEH(oTmpTab)
    local lRet := .t.
    local lOk := .t.
    local cQuery := ''
    local aVEHFields := {}
    local oBulkVEH := FwBulk():new(RetSQLName("VEH"), 850)
    local cRealName := oTmpTab:GetTableNameForQuery()
    local cAlias := ''
    local aFils := OA538015J_VerificaAcessoExclusivo("VEH")
    local nX := 0

    aVEHFields := {;
        {"VEH_FILIAL"},; 
        {"VEH_TIPO"},;
        {"VEH_GRUKIT"},; 
        {"VEH_CODKIT"},; 
        {"VEH_DESKIT"},; 
        {"VEH_VALKIT"};
    }

    oBulkVEH:setFields(aVEHFields)

    for nx := 1 to len(aFils)
        cQuery := " SELECT "
        cQuery += "     T.CODKIT, "
        cQuery += "     T.GRUPO, "
        cQuery += "     B1.B1_DESC AS DESKIT "
        cQuery += " FROM " + cRealName + " T "
        cQuery += " LEFT JOIN " + RetSQLName("SB1") + " B1 "
        cQuery += "     ON B1.B1_CODITE = T.CODITE "
        cQuery += "     AND B1.B1_GRUPO = T.GRUPO "
        cQuery += "     AND B1.B1_COD = T.CODIGO "
        cQuery += "     AND B1.D_E_L_E_T_ = ' ' "
        cQuery += " WHERE 
        cQuery += "     T.SEGMENTO = '06' "
        cQuery += "     AND T.CODKIT <> ' ' "
        cQuery += "     AND NOT EXISTS ( "
        cQuery += "     SELECT 1 FROM "+RetSQLName("VEH")+" VEH "
        cQuery += "     WHERE VEH.VEH_FILIAL =  '"+aFils[nx]+"' "
        cQuery += "         AND VEH.VEH_CODKIT = T.CODKIT "
        cQuery += "         AND VEH.VEH_GRUKIT = T.GRUPO "
        cQuery += "         AND VEH.VEH_TIPO = '2' " //chumbado no fonte original ofia440
        cQuery += "         AND VEH.D_E_L_E_T_ = ' ' "
        cQuery += "         AND T.CODKIT <> ' ' "
        cQuery += ")"

        cAlias := GetNextAlias()

        dbUseArea(.t., "TOPCONN", TcGenQry(,,cQuery), cAlias, .f., .t.)
        while !(cAlias)->(eof())
            oBulkVEH:addData({;
                aFils[nx],; //filial
                "2",; //tipo 2 seguindo a rotina OFIIA440 ele foi chumbado lá como tipo 2 
                (cAlias)->GRUPO,; //grukit
                (cAlias)->CODKIT,; //codkit
                (cAlias)->DESKIT,; //deskit
                0; //valkit valor que foi chumbado na rotina original OFIIA440
            })

            (cAlias)->(dbSkip())
        endDo
        (cAlias)->(dbCloseArea())
        oBulkVEH:flush()
    next

    lOk := oBulkVEH:Close()
    if .not. lOk
        OA538003J_LogaExecucao(cOrigem, STR0008, OA538004J_ParametrosString(oBulkVEH:getError() + " VEH")) //Erro
    else
        OA538003J_LogaExecucao(cOrigem, STR0013, OA538004J_ParametrosString("VEH SALVA")) //Sucesso //"VEH SALVA"
        OA538013J_VerificaEGravaVE8(oTmpTab)
    endif
    oBulkVEH:destroy()
    freeObj(oBulkVEH)
    fwFreeArray(aVEHFields)
Return lRet 

/*/{Protheus.doc} OA538013J_VerificaEGravaVE8
    Função que irá verificar, gravar ou atualizar a tabela VE8
    Se o registro não existir vai pro bulk insert
    Se existir vou atualizar ele
    A VE8 é uma tabela filho da VEH
    @type  Static Function
    @author Renan Migliaris
    @since 18/09/2025
/*/
Static Function OA538013J_VerificaEGravaVE8(oTmpTab)
    local lRet := .t.
    local lOk := .t.
    local cQuery := ''
    local aVE8Fields := {}
    local oBulkVE8 := FwBulk():new(RetSQLName("VE8"), 850)
    local cRealName := oTmpTab:GetTableNameForQuery()
    local cAlias := ''
    local aFils := OA538015J_VerificaAcessoExclusivo("VE8")
    local nX := 0

    aVE8Fields := {;
        {"VE8_FILIAL"},; 
        {"VE8_TIPO"},; 
        {"VE8_GRUKIT"},; 
        {"VE8_CODKIT"},; 
        {"VE8_GRUITE"},; 
        {"VE8_CODITE"},; 
        {"VE8_QTDADE"};
    }

    oBulkVE8:setFields(aVE8Fields)

    for nx := 1 to len(aFils)
        cQuery := " SELECT "
        cQuery += "  T.CODKIT, "
        cQuery += "  T.GRUPOKIT, "
        cQuery += "  T.CODITE, "
        cQuery += "  T.QTDADE, "
        cQuery += "  T.GRUPO "
        cQuery += " FROM " + cRealName + " T "
        cQuery += " WHERE "
        cQuery += "     T.SEGMENTO = '06' "
        cQuery += "     AND T.CODKIT <> ' ' "
        cQuery += "     AND T.GRUPOKIT <> ' ' "
        cQuery += "     AND NOT EXISTS ( "
        cQuery += "     SELECT 1 FROM "+RetSQLName("VE8")+" VE8 "
        cQuery += "     WHERE VE8.VE8_FILIAL =  '"+aFils[nx]+"' "
        cQuery += "        AND VE8.VE8_GRUKIT = T.GRUPOKIT "
        cQuery += "        AND VE8.VE8_CODKIT = T.CODKIT "
        cQuery += "        AND VE8.VE8_GRUITE = T.GRUPO "
        cQuery += "        AND VE8.VE8_CODITE = T.CODITE "
        cQuery += "        AND VE8.D_E_L_E_T_ = ' ' "
        cQuery += "        AND T.CODKIT <> ' ' "
        cQuery += "        AND T.GRUPOKIT <> ' ' "
        cQuery += "        AND T.CODITE <> ' ' "
        cQuery += "        AND T.GRUPO <> ' ' "
        cQuery += " )"

        cAlias := GetNextAlias()

        dbUseArea(.t., "TOPCONN", TcGenQry(,,cQuery), cAlias, .f., .t.)
        while !(cAlias)->(eof())
            oBulkVE8:addData({;
                aFils[nx],; //filial
                "1",; //tipo 1 seguindo a rotina OFIIA440 ele foi chumbado lá como tipo 2 
                (cAlias)->GRUPOKIT,; //grukit
                (cAlias)->CODKIT,; //codkit
                (cAlias)->GRUPO,; //gruitem
                (cAlias)->CODITE,; //codite
                (cAlias)->QTDADE; //qtidade
            })

            (cAlias)->(dbSkip())
        endDo
        (cAlias)->(dbCloseArea())
        oBulkVE8:flush()
    next
    lOk := oBulkVE8:Close()
    if .not. lOk
        OA538003J_LogaExecucao(cOrigem, STR0008, OA538004J_ParametrosString(oBulkVE8:getError() + " VE8")) //Erro
    else
        OA538003J_LogaExecucao(cOrigem, STR0013, OA538004J_ParametrosString("VE8 SALVA")) //Sucesso //"VE8 SALVA"
    endif
    oBulkVE8:destroy()
    freeObj(oBulkVE8)
    fwFreeArray(aVE8Fields)
Return lRet

/*/{Protheus.doc} OA538014J_CriaTabelaTemporaria
    Função que vai criar a tabela temporária que irá armazenar os dados do arquivo glass
    A tabela temporária será destruída no final do processamento
    A partir dela que as demais "alimentações" das tabelas serão feitas
    @type  Static Function
    @author user
    @since 17/09/2025
    @version version
    @param param_name, param_type, param_descr
    @return return_var, return_type, return_description
    @example
    (examples)
    @see (links_or_references)
/*/
Static Function OA538014J_CriaTabelaTemporaria(oFile)
    local lRet := .t.
    local aBulkFie := {}
    local aFields := {}
    local cCenCus := ''
    local cDesmar := ''
    local cCtaCtb := ''
    local cGruIte := ''
    local cRealName := ''
    local nCont := 0
    local cLinha := ''
    local nLinha := 0
    local nX := 0
    local nTFabr := TamSX3("B1_FABRIC")[1]
    local oItem := nil
    local oBulk := nil
    local cNumSeq := Strzero(0,TamSX3("VE9_NROSEQ")[1])
    
    cGruIte := MV_PAR01

    DbSelectArea('VE4')
    DbSetOrder(1)
    DbSeek(xFilial('VE4'))

    if !Empty(MV_PAR02)
        cCenCus := alltrim(MV_PAR02)
    else 
        cCencus := VE4->VE4_CENCUS
    endif

    if !Empty(MV_PAR03)
        cCtaCtb := alltrim(MV_PAR03)
    else 
        cCtaCtb := VE4->VE4_CTACTB
    endif

    aadd(aFields, {"CODIGO", "C", TamSX3("B1_COD")[1], TamSX3("B1_COD")[2]})
    aadd(aFields, {"GRUPO", "C", TamSX3("B1_GRUPO")[1], TamSX3("B1_GRUPO")[2]})
    aadd(aFields, {"CODITE", "C", TamSX3("B1_CODITE")[1], TamSX3("B1_CODITE")[2]})
    aadd(aFields, {"FABRIC", "C", TamSX3("B1_FABRIC")[1], TamSX3("B1_FABRIC")[2]})
    aadd(aFields, {"DESCRIC", "C", TamSX3("B1_DESC")[1], TamSX3("B1_DESC")[2]})
    aadd(aFields, {"UM", "C", TamSX3("B1_UM")[1], TamSX3("B1_UM")[2]})
    aadd(aFields, {"SEGUM", "C", TamSX3("B1_SEGUM")[1], TamSX3("B1_SEGUM")[2]})
    aadd(aFields, {"TIPO", "C", TamSX3("B1_TIPO")[1], TamSX3("B1_TIPO")[2]})
    aadd(aFields, {"LOCPAD", "C", TamSX3("B1_LOCPAD")[1], TamSX3("B1_LOCPAD")[2]})
    aadd(aFields, {"PICM", "N", TamSX3("B1_PICM")[1], TamSX3("B1_PICM")[2]})
    aadd(aFields, {"IPI", "N", TamSX3("B1_IPI")[1], TamSX3("B1_IPI")[2]})
    aadd(aFields, {"PRV1", "N", TamSX3("B1_PRV1")[1], TamSX3("B1_PRV1")[2]})
    aadd(aFields, {"CONTA", "C", TamSX3("B1_CONTA")[1], TamSX3("B1_CONTA")[2]})
    aadd(aFields, {"CENTRO", "C", TamSX3("B1_CC")[1], TamSX3("B1_CC")[2]})
    aadd(aFields, {"PESO", "N", TamSX3("B1_PESO")[1], TamSX3("B1_PESO")[2]})
    aadd(aFields, {"TIPOCQ", "C", TamSX3("B1_TIPOCQ")[1], TamSX3("B1_TIPOCQ")[2]})
    aadd(aFields, {"ORIGEM", "C", TamSX3("B1_ORIGEM")[1], TamSX3("B1_ORIGEM")[2]})
    aadd(aFields, {"CLASFIS", "C", TamSX3("B1_CLASFIS")[1], TamSX3("B1_CLASFIS")[2]})
    aadd(aFields, {"SEQVE9", "C", TamSX3("VE9_NROSEQ")[1], TamSX3("VE9_NROSEQ")[2]})
    aadd(aFields, {"NROSUBVE9", "C", TamSX3("VE9_NROSUB")[1], TamSX3("VE9_NROSUB")[2]})
    aadd(aFields, {"ITENOV", "C", TamSX3("VE9_ITENOV")[1], TamSX3("VE9_ITENOV")[2]})
    aadd(aFields, {"ITEANT", "C", TamSX3("VE9_ITEANT")[1], TamSX3("VE9_ITEANT")[2]})
    aadd(aFields, {"STAGLA", "C", TamSX3("VE9_STAGLA")[1], TamSX3("VE9_STAGLA")[2]})
    aadd(aFields, {"APLICA", "C", TamSX3("VE9_APLICA")[1], TamSX3("VE9_APLICA")[2]})
    aadd(aFields, {"QTDADE", "N", TamSX3("VE9_QTDADE")[1], TamSX3("VE9_QTDADE")[2]})
    aadd(aFields, {"DATSUB", "D", TamSX3("VE9_DATSUB")[1], TamSX3("VE9_DATSUB")[2]})
    aadd(aFields, {"QTDSUB", "N", TamSX3("VE9_QTDSUB")[1], TamSX3("VE9_QTDSUB")[2]})
    aadd(aFields, {"STATUS", "C", TamSX3("VE9_STATUS")[1], TamSX3("VE9_STATUS")[2]})
    aadd(aFields, {"SEGMENTO", "C", TamSX3("VE9_SEGMEN")[1], TamSX3("VE9_SEGMEN")[2]})
    aadd(aFields, {"CODKIT", "C", TamSx3("VE8_CODKIT")[1], TamSX3("VE8_CODKIT")[2]})
    aadd(aFields, {"GRUPOKIT", "C", TamSx3("VE8_GRUKIT")[1], TamSX3("VE8_GRUKIT")[2]})

    cAliasTmp := GetNextAlias()
    oTmpTab := FWTemporaryTable():new(cAliasTmp) 
    oTmpTab:setFields(aFields)
    oTmpTab:addIndex("1", {"CODIGO"})

    for nX := 1 to len(aFields)
        aadd(aBulkFie, {aFields[nx][1]})
    next

    oTmpTab:Create() 

    DbSelectArea("VE1")
    DbSetOrder(1)
    DbSeek(xFilial("VE1") + VE4->VE4_PREFAB)

    cDesmar := Left(VE1->VE1_DESMAR, nTFabr)

    cRealName := oTmpTab:GetTableNameForTCFunctions() //função para pegar o nome para ser usada em outras funções do DBAccess
    
    
    oBulk := FwBulk():new(cRealName)
    oBulk:setFields(aBulkFie)

    while oFile:hasLine()
        nCont++
        cNumSeq := soma1(cNumSeq)
        cLinha := oFile:GetLine()
        oItem := OA538011J_MontaItemDeAcordoComOSeguimento(cLinha)
        if Left(cLinha,2) == "01" .or. Left(cLinha,2) == "04" .or. Left(cLinha,2) == "06" .or. Left(cLinha,2) == "02"
            oBulk:addData({;
                oItem["CODIGO"],;                              // CODIGO
                cGruIte,;                                      // GRUPO
                oItem["CODITE"],;                              // CODITE
                cDesmar,;                                      // FABRIC
                oItem["DESCRICAO"],;                           // DESCRIC
                "PC",;                                         // UM
                "PC",;                                         // SEGUM
                "ME",;                                         // TIPO
                alltrim(MV_PAR04),;                            // LOCPAD
                0,;                                            // PICM 
                0,;                                            // IPI 
                0,;                                            // PRV1 
                cCtaCtb,;                                      // CONTA
                cCenCus,;                                      // CENTRO
                1,;                                            // PESO 
                "M",;                                          // TIPOCQ 
                "0",;                                          // ORIGEM 
                "00",;                                         // CLASFIS 
                cNumSeq,;                                      // SEQVE9
                Strzero(nCont,TamSX3("VE9_NROSUB")[1]),;       // NROSUBVE9 //Soma1 com tamanho 6
                oItem["ITENOV"],;                              // ITENOV
                oItem["ITEANT"],;                              // ITEANT
                oItem["STAGLA"],;                              // STAGLA
                oItem["APLICA"],;                              // APLICA 
                oItem["QTDADE"],;                              // QTDADE
                oItem["DATSUB"],;                              // DATSUB
                oItem["QTDSUB"],;                              // QTDSUB
                oItem["STATUS"],;                              // STATUS
                oItem["SEGMENTO"],;                            // SEGMENTO
                oItem["CODKIT"],;                              // CODKIT
                cGruIte;                                       // GRUPOKIT
            })
        endif
        nLinha++
    endDo
    oBulk:flush()
    oBulk:Close()
    oBulk:destroy()
    
    fwFreeArray(aFields)
    fwFreeArray(aBulkFie)
    freeObj(oBulk)
Return lRet

/*/{Protheus.doc} OA538015J_VerificaAcessoExclusivo
    Vai verificar se o acesso é exclusivo.
    Se o acesso for compartilhado vai retornar um array de filiais com o xFilial do alias recebido
    Caso contrário a função que chamar aqui vai usar a private aFilAux
    @type  Static Function
    @author Renan Migliaris
    @since 18/09/2025
/*/
Static Function OA538015J_VerificaAcessoExclusivo(cAlias)
    local aRet := {}

    if FWModeAccess(cAlias, 3) == "E"
        aRet := aClone(aFilAux)
    else
        aRet := {xFilial(cAlias)} 
    endif

Return aRet


/*/{Protheus.doc} OA538016J
    Valida o grupo da peça informado no parâmetro MV_PAR01
    @type  Function
    @author Renan Migliaris
    @since 19/09/2025
    /*/
Function OA538016J()
    local lRet := .t.
    DbSelectArea("SBM")
    DbSetOrder(1)
    
    if !Empty(MV_PAR01) .and. (DbSeek(xFilial("SBM") + MV_PAR01))
        lRet := .t.
    else
        FMX_HELP(STR0005, STR0026) //OFIA538 //"Grupo Padrão da Peça Inválido"
        lRet := .f.
    endif
    dbCloseArea()
Return lRet

/*/{Protheus.doc} OA538016J
    Valida o MV_PAR02 Conta Padrão
    @type  Function
    @author Renan Migliaris
    @since 19/09/2025
    /*/
Function OA538017J()
    local lRet := .t.
    DbSelectArea("CT1")
    DbSetOrder(1)
    if !Empty(MV_PAR02)
        If !DbSeek(xFilial("CT1") + MV_PAR02)
            FMX_HELP(STR0005, STR0025) //"OFIA538" //"Conta Contábil Padrão da Peça Inválida"
            lRet := .f.
        EndIf
    endif
    dbCloseArea()
Return lRet

/*/{Protheus.doc} OA538017J
    Valida o MV_PAR03 CTT
    @type  Function
    @author Renan Migliaris
    @since 19/09/2025
    /*/
Function OA538018J()
    local lRet := .t. 
    DbSelectArea("CTT")
    DbSetOrder(1)

    if !Empty(MV_PAR03)
        If !DbSeek(xFilial("CTT") + MV_PAR03)
            FMX_HELP(STR0005, STR0024) //"OFIA538" //"Centro de Custo Padrão da Peça Inválido"
            lRet := .f.
        EndIf
    endif
    dbCloseArea()
Return lRet


/*/{Protheus.doc} OA538018J
    Valida o MV_PAR04 Localização Padrão
    @type  Function
    @author Renan Migliaris
    @since 19/09/2025
    /*/
Function OA538019J()
    local lRet := .t.
    DbSelectArea("NNR")
    DbSetOrder(1)
    
    if !Empty(MV_PAR04) .and. (DbSeek(xFilial("NNR") + MV_PAR04))
        lRet := .t.
    else
        FMX_HELP(STR0005, STR0023) //"OFIA538" //"Localização Padrão da Peça Inválida"
        lRet := .f.
    endif
    dbCloseArea()
Return lRet

/*/{Protheus.doc} OA538020J_SetaFieldsBulk
    Verifica os arrays de fields que podem vir ou não do ponto de entrada
    Seta o bulk da maneira correta com o array certo 
    Manipula o objeto pra fazer esse insert bulk 
    @type  Static Function
    @author Renan Migliaris
    @since 26/09/2025
/*/
Static Function OA538020J_SetaFieldsBulk(oBulk, aFields, aFielAux)
    local nX := 0

    if (valtype(aFielAux) == "A") .and. (len(aFielAux) > 0)
        for nx := 1 to len(aFielAux)
            aadd(aFields, aFielAux[nx])
        next
    endif

    oBulk:setFields(aFields)
Return

/*/{Protheus.doc} OA538021J_SetaODadoDoItem
    Mesma coisa da setaField só que com o dado do item
    @type  Static Function
    @author Renan Migliaris
    @since 26/09/2025
/*/
Static Function OA538021J_SetaODadoDoItem(oBulk, aDado, aNewDado)
    if (valtype(aNewDado) == "A") .and. len(aNewDado) > 0
        oBulk:addData(aNewDado[1])
    else
        oBulk:addData(aDado[1])
    endif
Return


/*/{Protheus.doc} OA538022J_ValidaSelecaoDeArquivosPergunte
    Valida a seleção dos arquivos
	@type Function
	@author Renan Migliaris
	@since 17/10/2025
/*/
Function OA538022J_ValidPerg()

	Local lRet 		:= .T.

    if ReadVar() == 'MV_PAR07' .and. MV_PAR06 == 2
        MV_PAR07 := cGetFile(STR0030, STR0031, , "SERVIDOR", .T., GETF_RETDIRECTORY, .T., .T. ) //"Diretório" //"Glass-Scania"
    endif

Return lRet
/*/{Protheus.doc} schedDef
    Função padrão scheduler
    @type  Static Function
    @author Renan Migliaris
    @since 22/08/2025
/*/
Static Function schedDef()
    local aParam := {;
        "P",;
        "OFIA538",;
        "",;
        "",;
        "";
    }
Return aParam#include "Protheus.ch"
#include 'TOPCONN.ch'
#include 'OFIA538.ch'

/*/{Protheus.doc} OFIA538
    GLASS - SCANIA
    @type  Function
    @author Renan Migliaris
    @since 20/08/2025
    /*/
Function OFIA538()
    local aArea := FwGetArea()
    local lRet := .f.
    local lFunc := .t.
    private lPePro := ExistBlock("OF538PRO")
    private lPeFim := ExistBlock("OF538FIM")
    private lSched := FWGetRunSchedule()
    private cOrigem := ""
    private cPerg := "OFIA538"
    private lPEnt := ExistBlock("IA440DPG") //questão da chamada de ponto de entrada
    private lGruNov := (VE9->(FieldPos("VE9_GRUNOV"))>0)
    private cBZB5 := GetNewPar("MV_CADPROD", '')
    private nValor := 0
    private aFilAtu := FWArrFilAtu()
    private aFilAux := FWAllFilial(aFilAtu[3] , aFilAtu[4] , aFilAtu[1] , .f.) //traz todas as filiais aqui
    private oTmpTab := nil
    private cAliasTmp := ''
    default lEnd := .t.
    

    if lSched
        cOrigem := STR0001 //Scheduler
    else
        cOrigem := STR0002 //Menu
    endif

    if !lSched
        while pergunte(cPerg, !lSched)
            if OA538001J_VerificaPerguntePreenchido()
                FWMsgRun(,{|| OA538002J_ProcessaArquivo(@lFUnc), STR0004})
                if lFunc
                    FWAlertSuccess(STR0005, STR0006) //'OFIA538' //'Arquivo Processado Com Sucesso!'
                    lRet := .t.
                else
                    FMX_HELP(STR0005, STR0027) //OFIA538 //'Uma ou mais perguntas obrigatórias não foram preenchidas corretamente! Verifique as informações e tente novamente.'
                    OA538003J_LogaExecucao(cOrigem, STR0008, OA538004J_ParametrosString(STR0009), .t.) //"Erro" //"Erro execução via menu"
                    lRet := .f.
                endif
                Exit
            end
        endDo
    else
        if OA538001J_VerificaPerguntePreenchido()
            OA538002J_ProcessaArquivo(@lFunc)
            lRet := lFunc
        else   
            OA538003J_LogaExecucao(cOrigem, STR0008, OA538004J_ParametrosString(STR0029), .t.) //"Erro" //"Erro execução via scheduler"
            lRet := .f.
        endif
    endif

    if lPeFim .and. lRet
        ExecBlock("OF538FIM", .f., .f.)
    endif
    RestArea(aArea)
Return lRet

/*/{Protheus.doc} OA538001J_VerificaPerguntePreenchido
    Verificação do eprgunte preenchido
    @author Renan Migliaris
    @since 21/08/2025
/*/
Static Function OA538001J_VerificaPerguntePreenchido()
    local lRet := .t.
    local cExt := alltrim(upper(ExtractExt(MV_PAR05)))
    local aErros := {}
    local cMsg := ''
    local oX1Hlp := FwSX1Util():new()
    local aPergs := {}
    local nX := 0
    local lExistDir := .f.
    local nPar06 := 0

    oX1Hlp:AddGroup(cPerg)
    oX1Hlp:SearchGroup()
    aPergs := oX1Hlp:GetGroup(cPerg)

    if Empty(MV_PAR05) .or. (cExt <> '.DAT')
        aadd(aErros, STR0028)
    endif

    if ValType(MV_PAR06) <> "N"
        nPar06 := 0
    else
        nPar06 := MV_PAR06
    endif

    if (nPar06 == 2) .and. (!Empty(MV_PAR07))
        lExistDir := ExistDir(alltrim(MV_PAR07))
        if !lExistDir
            aadd(aErros, aPergs[2][7]:CX1_PERGUNT)
            lRet := .f.
        endif
    endif

    if len(aErros) > 0 
        if !lSched
            for nx := 1 to len(aErros)
                cMsg += alltrim(aErros[nx])
            next
            FMX_HELP(STR0008, STR0022 + alltrim(cMsg)) //"Erro" //"Os seguintes parâmetros não foram preenchidos corretamente: "
        endif
        lRet := .f.
    endif

Return lRet

/*/{Protheus.doc} OA538002J_ProcessaArquivo()
    Realiza o processamento do arquivo .Dat enviado
    @type  Static Function
    @author Renan Migliaris
    @since 21/08/2025
/*/
Static Function OA538002J_ProcessaArquivo(lRet)
    local cFile := alltrim(MV_PAR05)
    local nAcaoArq := MV_PAR06
    local oFile := FwFileReader():new(cFile)
    local cDest := ''
    local cArqOrig := ''
    local lCopy := .f.
    default lRet := .t.
 
    OA538003J_LogaExecucao(cOrigem, STR0012, OA538004J_ParametrosString()) //"Início"
    if (oFile:Open())
        cArqOrig := alltrim(lower(MV_PAR05))
        OA538005J_PreparaVE9()

        OA538006J_ProcessaArquivoGlass(@oFile)

        lRet := .t.
        oFile:Close()
        OA538003J_LogaExecucao(cOrigem, STR0013, STR0014, .t.) //"Sucesso" //"Processado com sucesso"
        Do Case
            Case nAcaoArq == 2
                cDest := alltrim(lower(alltrim(MV_PAR07)+ "\" + SubStr(cFile, Rat("\", cFile) + 1)))
                lCopy := __CopyFile(cArqOrig, alltrim(lower(cDest)))
                if lCopy
                    oFile:erase()
                endIF
            Case nAcaoArq == 3
                oFile:erase()
        EndCase
    else
        lRet := .f.
        OA538003J_LogaExecucao(cOrigem, STR0008, OA538004J_ParametrosString(STR0015), .t.) //Erro //"Não foi possível realizar a abertura do arquivo"
    endif
Return lRet

/*/{Protheus.doc} OA538003J_LogaExecucao()
    Realiza o log da operação. 
    @type  Static Function
    @author Renan Migliaris
    @since 21/08/2025
/*/
Static Function OA538003J_LogaExecucao(cOrigem, cTipo, cMensagem, lHorFin)
    local aData := {}
    local oLogger := DMS_Logger():new()
    default lHorFin := .f.

    
    aadd(adata, {"VQL_AGROUP", "OFIA538"})
    aadd(adata, {"VQL_FILORI", cFilAnt})
    aadd(adata, {"VQL_TIPO", cTipo})
    aadd(adata, {"VQL_MSGLOG", cMensagem})
    aadd(adata, {"VQL_DADOS", cOrigem})
    if lHorFin
        aadd(aData, {"VQL_HORAF", VAL(STRTRAN(SUBSTR( TIME() , 1, 5), ":", "" ))})
        aadd(adata, {"VQL_DATAF", dDataBase})
    endif

    oLogger:LogToTable(aData)
Return

/*/{Protheus.doc} OA538004J_ParametrosString
    Função que vai guardar os parâmetros que foram recebidos pela função para finalidade de log
    Os parâmetros serão guardados no formato json
    @type  Static Function
    @author Renan Migliaris
    @since 22/08/2025
/*/
Static Function OA538004J_ParametrosString(cMsgErro)
    local cParams := ''
    local oParams := JsonObject():new()
    default cMsgErro := ''

    oParams["MV_PAR01"] := MV_PAR01
    oParams["MV_PAR02"] := MV_PAR02
    oParams["MV_PAR03"] := MV_PAR03
    oParams["MV_PAR04"] := MV_PAR04
    oParams["MV_PAR05"] := MV_PAR05
    oParams["MV_PAR06"] := MV_PAR06
    oParams["MV_PAR07"] := MV_PAR07
    if !Empty(cMsgErro)
        oParams["MSG_ERRO"] := cMsgErro
    endif

    cParams := oParams:toJson()

    freeObj(oParams)
Return cParams

/*/{Protheus.doc} OA538005J_PreparaVE9
    Função que irá realizar a preparação da VE9 para uma nova importação
    @type  Static Function
    @author Renan Migliaris
    @since 25/08/2025    
/*/
Static Function OA538005J_PreparaVE9()
    local oStatement := FWPreparedStatement():New()
    local cQuery := ''
    local cFinalQuery := ''
    local cVeFilial := ''
    DbSelectArea("VE9")
    cVeFilial := xFilial('VE9')
    
    Do Case
        Case Empty(cVeFilial)
            //truncate não vai passar linha a linha deletando o que vai gerar mais performance quando apagar a VE9 
            //tabela será trucanda em casos que a VE9 seja compartilhada
            cQuery := " TRUNCATE TABLE " + RetSQLName('VE9')
            oStatement:SetQuery(cQuery)
        Otherwise
            cQuery := " DELETE FROM " +RetSQLName("VE9")
            cQuery += " WHERE VE9_FILIAL = ? "
            oStatement:SetQuery(cQuery)
            oStatement:SetString(1, cVeFilial)
    EndCase
    
    cFinalQuery := oStatement:GetFixQuery()

    if TCSqlExec(cFinalQuery) < 0
        OA538003J_LogaExecucao(cOrigem, STR0008, OA538004J_ParametrosString(STR0016), .t.) //Erro //"Não foi possível a execução do statement na tabela VE9. Verifique se a tabela está disponível"
        return .f.
    endif 
Return .t.

/*/{Protheus.doc} OA538006J_ProcessaArquivoGlass
    Realiza o processamento do arquivo .dat (glass)
    @type  Static Function
    @author Renan Migliaris
    @since 25/08/2025
/*/
Static Function OA538006J_ProcessaArquivoGlass(oFile)
    local lRet := .t.

    if OA538014J_CriaTabelaTemporaria(@oFile)
        OA538008J_GravaVE9(@oTmpTab)
        OA538007J_VerificaEGravaSb1(@oTmpTab)
        
        If "SB5" $ cBZB5
            OA538009J_VerificaEGravaSb5(@oTmpTab)
        EndIf

        If "SBZ" $ cBZB5
            OA538010J_VerificaEGravaSBZ(@oTmpTab)
        EndIf

        OA538012J_VerificaEGravaVEH(@oTmpTab) //a gravação da VE8 está sendo chamada de dentro da função de gravação da VEH e somente se a gravação da VEH der certo
        oTmpTab:Delete()
    endif 
Return lRet

/*/{Protheus.doc} OA538007J_VerificaEGravaSb1
    Verifica via query quais os registros que não existem na SB1 
    Caso não existirem eu já faço a inclusão deles via bulk
    Mando a tmpTable aqui como parâmetro para acessar seus respectivos métodos do objeto como por exemplo o realname
    @type  Static Function
    @author Renan Migliaris
    @since 27/08/2025
/*/
Static Function OA538007J_VerificaEGravaSb1(oTmpTab)
    local cQuery := ''
    local cRealName := oTmpTab:GetTableNameForQuery()
    local cAlias := ''
    local nX := 0
    local lOk := .t.
    local aFields := {}
    local aFieAux := {}
    local aItem := {}
    local aItAux := {}
    local aFils := OA538015J_VerificaAcessoExclusivo("SB1")
    local oBulkB1 := FwBulk():new(RetSQLName('SB1'), 850)

    aFields := { ;
        {"B1_FILIAL"}, {"B1_COD"}, {"B1_GRUPO"}, {"B1_CODITE"}, {"B1_FABRIC"}, {"B1_DESC"}, ;
        {"B1_UM"}, {"B1_SEGUM"}, {"B1_TIPO"}, {"B1_LOCPAD"}, {"B1_PICM"}, ;
        {"B1_IPI"}, {"B1_PRV1"}, {"B1_CONTA"}, {"B1_CC"}, {"B1_PESO"}, ;
        {"B1_TIPOCQ"}, {"B1_ORIGEM"}, {"B1_CLASFIS"} ;
    }

    if lPePro
        aFieAux := ExecBlock("OF538PRO", .f., .f., {"SB1", .t.})
    endif

    OA538020J_SetaFieldsBulk(@oBulkB1, @aFields, aFieAux)
    
    for nX := 1 to len(aFils)
        cQuery := " SELECT " 
        cQuery += "    T.CODIGO, "
        cQuery += "    T.GRUPO, "
        cQuery += "    T.CODITE, "
        cQuery += "    T.FABRIC, "
        cQuery += "    T.DESCRIC, "
        cQuery += "    T.UM, "
        cQuery += "    T.SEGUM, "
        cQuery += "    T.TIPO, "
        cQuery += "    T.LOCPAD, "
        cQuery += "    T.PICM, "
        cQuery += "    T.IPI, "
        cQuery += "    T.PRV1, "
        cQuery += "    T.CONTA, "
        cQuery += "    T.CENTRO, "
        cQuery += "    T.PESO, "
        cQuery += "    T.TIPOCQ, "
        cQuery += "    T.ORIGEM, "
        cQuery += "    T.CLASFIS "
        cQuery += " FROM " + cRealName + " T "
        cQuery += " WHERE "
        cQuery += "    T.SEGMENTO = '01' "
        cQuery += "    AND NOT EXISTS ( "
        cQuery += "    SELECT 1 FROM " + RetSQLName("SB1") + " SB1 "
        cQuery += "    WHERE SB1.B1_FILIAL = '" + aFils[nX] + "' "
        cQuery += "      AND SB1.B1_GRUPO  = T.GRUPO "
        cQuery += "      AND SB1.B1_CODITE = T.CODITE "
        cQuery += "      AND SB1.D_E_L_E_T_ = ' ' "
        cQuery += ")"

        cAlias := GetNextAlias()

        dbUseArea(.t., "TOPCONN", TcGenQry(,,cQuery), cAlias, .f., .t.)

        while !(cAlias)->(eof())
            aItem := {}
            aadd(aItem, {;
                aFils[nX],;
                (cAlias)->CODIGO,;
                (cAlias)->GRUPO,; 
                (cAlias)->CODITE,;
                (cAlias)->FABRIC,; 
                (cAlias)->DESCRIC,; 
                (cAlias)->UM,; 
                (cAlias)->SEGUM,;
                (cAlias)->TIPO,;
                (cAlias)->LOCPAD,;
                (cAlias)->PICM,;
                (cAlias)->IPI,;
                (cAlias)->PRV1,;
                (cAlias)->CONTA,;
                (cAlias)->CENTRO,;
                (cAlias)->PESO,;
                (cAlias)->TIPOCQ,;
                (cAlias)->ORIGEM,;
                (cAlias)->CLASFIS;
            })

            aItAux := aClone(aItem)

            if lPePro
                aItAux := ExecBlock("OF538PRO", .f., .f., {"SB1", .f. ,aItAux})
            endif

            OA538021J_SetaODadoDoItem(@oBulkB1, aItem, aItAux)

            fwFreeArray(aItem)
            fwFreeArray(aItAux)
            (cAlias)->(DbSkip())
        endDo

        (cAlias)->(dbCloseArea())
        oBulkB1:flush()
    next

    lOk := oBulkB1:Close()
    if .not. lOk
        OA538003J_LogaExecucao(cOrigem, STR0008, OA538004J_ParametrosString(oBulkB1:GetError() + " SB1")) //"ERRO"
    else
        OA538003J_LogaExecucao(cOrigem, STR0013, OA538004J_ParametrosString(STR0017)) //Sucesso //"SB1 SALVA"
    endif
    oBulkB1:Destroy()

    fwFreeArray(aFils)
    fwFreeArray(aFields)
    freeObj(oBulkB1)
Return lOk

/*/{Protheus.doc} OA538008J_GravaVE9
    Aqui já vou fazer o processamento da VE9 em outra thread. 
    Vou receber os parâmetros de filial + empresa 
    o terceiro elemento do array vai ser os dados a serem processados já filtrados pelo 01 
    Ou seja, vou montando o cLinha aqui para realizar o bulk da VE9
    @type Function
    @author Renan Migliaris
    @since 28/08/2025
/*/
Static Function OA538008J_GravaVE9(oTmpTab)
    local aVe9 := {}
    local cQuery := ''
    local lOk := .t.
    local cAlias := ''
    local cRealName := oTmpTab:GetTableNameForQuery()
    local oBulkVE9 := FwBulk():new(RetSQLName('VE9'), 850)
    local cMyFil := xFilial("VE9")
    
    aVE9 := {;
        {"VE9_FILIAL"}, {"VE9_NROSEQ"}, {"VE9_NROSUB"}, {"VE9_GRUITE"},;
        {"VE9_ITEANT"}, {"VE9_ITENOV"}, {"VE9_SEGMEN"}, {"VE9_STAGLA"},;
        {"VE9_APLICA"}, {"VE9_STATUS"}, {"VE9_DATSUB"}, {"VE9_QTDADE"},; 
        {"VE9_QTDSUB"};
    }

    oBulkVE9:setFields(aVe9)

    cQuery := "SELECT "
    cQuery += "    T.SEQVE9, "
    cQuery += "    T.NROSUBVE9, "
    cQuery += "    T.ITENOV, "
    cQuery += "    T.GRUPO, "
    cQuery += "    T.ITEANT, "
    cQuery += "    T.SEGMENTO, "
    cQuery += "    T.STAGLA, "
    cQuery += "    T.APLICA, "
    cQuery += "    T.STATUS, "
    cQuery += "    T.DATSUB, "
    cQuery += "    T.QTDADE, "
    cQuery += "    T.QTDSUB "
    cQuery += "FROM " + cRealName + " T"
    cQuery += " WHERE T.SEGMENTO IN ('01','02','04','06') "
    cAlias := GetNextAlias()
    
    dbUseArea(.t., "TOPCONN", TcGenQry(,,cQuery), cAlias, .f., .t.)

    while !(cAlias)->(eof())
        oBulkVE9:addData({;
            cMyFil,;
            (cAlias)->SEQVE9,;
            (cAlias)->NROSUBVE9,;
            (cAlias)->GRUPO,;
            (cAlias)->ITEANT,;
            (cAlias)->ITENOV,;
            (cAlias)->SEGMENTO,;
            (cAlias)->STAGLA,;
            (cAlias)->APLICA,;
            (cAlias)->STATUS,;
            (cAlias)->DATSUB,;
            (cAlias)->QTDADE,;
            (cAlias)->QTDSUB;
        })
        (cAlias)->(DbSkip())
    end

    oBulkVE9:flush()
    lOk := oBulkVE9:Close()
    oBulkVE9:destroy()

    (cAlias)->(dbCloseArea())
    if lOk
        OA538003J_LogaExecucao(cOrigem, STR0013, OA538004J_ParametrosString(STR0018), .t.)
    else
        OA538003J_LogaExecucao(cOrigem, STR0008, OA538004J_ParametrosString(oBulkVE9:GetError() + " VE9"), .t.)
    endif
    freeObj(oBulkVE9)
Return lOk

/*/{Protheus.doc} OA538009J_VerificaEGravaSb5
    Aqui vou ver quais itens que estão na SB5 e que precisarão ser atualizados. 
    Recebo o array aqui faço um batch no banco de dados e obtenho o retorno do que precisa ser atualizado.
    A busca será feita pelo código do item e deverá considerar todas as filiais
    Primeiro item do aParams vai ser meu array para processamento da braba
    @type  Static Function
    @author Renan Migliaris
    @since 28/08/2025
/*/
Static Function OA538009J_VerificaEGravaSb5(oTmpTab)
    local lOk := .t.
    local aB5Fields := {}
    local nI := 0
    local oBulkB5 := FwBulk():new(RetSQLName("SB5"), 850)
    local cQuery := ''
    local cRealName := oTmpTab:GetTableNameForQuery()
    local cAlias := ''
    local aFils := OA538015J_VerificaAcessoExclusivo("SB5")
    local aFieAux := {}
    local aItAux := {}
    local aItem := {}

    aB5Fields := {;
        {"B5_FILIAL"}, {"B5_COD"}, {"B5_CEME"}, {"B5_UMIND"};
    }

    if lPePro
        aFieAux := ExecBlock("OF538PRO", .f., .f., {"SB5", .t.})
    endif

    OA538020J_SetaFieldsBulk(@obulkB5, @aB5Fields, aFieAux)

    for nI := 1 to len(aFils)
        cQuery := "SELECT T.CODIGO, T.DESCRIC FROM " + cRealName + " T "
        cQuery += " WHERE "
        cQuery += "     T.SEGMENTO = '01' "
        cQuery += "     AND NOT EXISTS ( "
        cQuery += "     SELECT 1 FROM "+ RetSQLName("SB5") + " SB5 "
        cQuery += "     WHERE SB5.B5_FILIAL = '" +aFils[ni]+"'" 
        cQuery += "         AND SB5.B5_COD = T.CODIGO "
        cQuery += "         AND SB5.D_E_L_E_T_ = ' ' "
        cQuery += " )"
        
        cAlias := GetNextAlias()

        dbUseArea(.t., "TOPCONN", TcGenQry(,,cQuery), cAlias, .f., .t.)

        while !(cAlias)->(eof())
            aItem := {}
            aadd(aItem,  {;
                aFils[ni],;
                (cAlias)->CODIGO,;
                (cAlias)->DESCRIC,;
                "1";
            })

            aItAux := aClone(aItem)

            if lPePro
                aItAux := ExecBlock("OF538PRO", .f., .f., {"SB5", .f., aItAux})
            endif
            
            OA538021J_SetaODadoDoItem(@oBulkB5, aItem, aItAux)

            fwFreeArray(aItem)
            fwFreeArray(aItAux)
            (cAlias)->(dbSkip())
        endDo
        (cAlias)->(dbCloseArea())
        oBulkB5:flush()
    next

    lOk := oBulkB5:Close()
    if .not. lOk
        OA538003J_LogaExecucao(cOrigem, STR0008, OA538004J_ParametrosString(oBulkB5:getError() + " SB5")) //erro
    else
        OA538003J_LogaExecucao(cOrigem, STR0013, OA538004J_ParametrosString(STR0019)) //Sucess //"SB5 SALVA"
    endif
    oBulkB5:destroy()

    fwFreeArray(aFils)
    fwFreeArray(aB5Fields)
    freeObj(obulkB5)
return lOk

/*/{Protheus.doc} OA538010J_VerificaEGravaSBZ
    Caso tiver o parâmetro da SBZ vai fazer a gravação dela nessa função aqui
    @type  Static Function
    @author Renan Migliaris
    @since 10/09/2025
/*/
Static Function OA538010J_VerificaEGravaSBZ(oTmpTab)
    local lOk := .t.
    local aBZFields := {}
    local nI := 0
    local oBulkBZ := FwBulk():new(RetSqlName("SBZ"), 850)
    local cQuery := ''
    local cRealName := oTmpTab:GetTableNameForQuery()
    local cAlias := ''
    local aFils := OA538015J_VerificaAcessoExclusivo("SBZ")
    local aFieAux := {}
    local aItem := {}
    local aItAux := {}

    aBZFields := {;
        {"BZ_FILIAL"}, {"BZ_COD"}, {"BZ_LOCPAD"};
    }
    
    if lPePro
        aFieAux := ExecBlock("OF538PRO", .f., .f., {"SBZ", .t.})
    endif

    OA538020J_SetaFieldsBulk(@oBulkBZ, @aBZFields, aFieAux)

    for ni := 1 to len(aFils)
        
        cQuery := " SELECT T.CODIGO, T.LOCPAD FROM " + cRealName + " T "
        cQuery += " WHERE "
        cQuery += "     T.SEGMENTO = '01' "
        cQuery += "     AND NOT EXISTS ( "
        cQuery += "     SELECT 1 FROM "+RetSqlName("SBZ")+" SBZ "
        cQuery += "     WHERE SBZ.BZ_FILIAL = '"+aFils[ni]+"' "
        cQuery += "         AND SBZ.BZ_COD = T.CODIGO "
        cQuery += "         AND SBZ.D_E_L_E_T_ = ' ' "
        cQuery += " )"

        cAlias := GetNextAlias()

        dbUseArea(.t., "TOPCONN", TcGenQry(,,cQuery), cAlias, .f., .t.)

        while !(cAlias)->(eof())
            aItem := {}
            aadd(aItem, {;
                aFilAux[ni],;
                (cAlias)->CODIGO,;
                (cAlias)->LOCPAD;
            })

            aItAux := aClone(aItem)

            if lPePro
                aItAux := ExecBlock("OF538PRO", .f., .f., {"SBZ", .f., aItAux})
            endif

            OA538021J_SetaODadoDoItem(@oBulkBZ, aItem, aItAux)

            fwFreeArray(aItem)
            fwFreeArray(aItAux)
            (cAlias)->(dbSkip())
        endDo

        (cAlias)->(dbCloseArea())
        oBulkBZ:flush()
    next

    lOk := oBulkBZ:Close()
    if .not. lOk
        OA538003J_LogaExecucao(cOrigem, STR0008, OA538004J_ParametrosString(oBulkBZ:getError())) //ERro
    else
        OA538003J_LogaExecucao(cOrigem, STR0013, OA538004J_ParametrosString(STR0020)) //"SUCESSO" //SBZ Salva
    endif
    oBulkBZ:destroy()


    fwFreeArray(aFils)
    fwFreeArray(aBZFields)
    freeObj(oBulkBZ)
Return lOk

/*/{Protheus.doc} OA538011J_MontaItemDeAcordoComOSeguimento
    Vai montar o Itenov de acordo com a linha recebida para a inserção na tabela temporária
    @type  Static Function
    @author Renan Migliaris
    @since 15/09/2025
/*/
Static Function OA538011J_MontaItemDeAcordoComOSeguimento(cLinha)
    Local oRetorno
    Local cSegmento := Left(cLinha, 2)

    oRetorno := JsonObject():new()
    oRetorno["CODIGO"] := UPPER(Subs(cLinha, 3, 7))
    oRetorno["CODITE"] := UPPER(Subs(cLinha, 3, 7))
    oRetorno["DESCRICAO"] := UPPER(Subs(cLinha, 10, 15))
    oRetorno["APLICA"] := ""
    oRetorno["ITEANT"] := UPPER(Subs(cLinha, 3, 7))
    oRetorno["SEGMENTO"] := cSegmento
    oRetorno["ITENOV"] := ""
    oRetorno["CODITE"] := ""
    oRetorno["STAGLA"] := ""
    oRetorno["QTDADE"] := 0
    oRetorno["DATSUB"] := ""
    oRetorno["QTDSUB"] := 0
    oRetorno["STATUS"] := ""
    oRetorno["CODKIT"] := ""

    Do Case
        Case cSegmento == "01" //informação básica do item
            oRetorno["ITENOV"] := UPPER(Subs(cLinha, 3, 7))
            oRetorno["CODITE"] := UPPER(Subs(cLinha, 3, 7))
            oRetorno["STAGLA"] := UPPER(Subs(cLinha, 55, 30))
        
        Case cSegmento == "02"
            oRetorno["APLICA"] := UPPER(Subs(cLinha, 10,35))
            oRetorno["ITENOV"] := UPPER(Subs(cLinha, 3, 7))

        Case cSegmento == "04" //informacoes substituo do item
            oRetorno["ITENOV"] := UPPER(Subs(cLinha, 10, 10))
            oRetorno["QTDADE"] := Val(Subs(cLinha, 20, 7))
            oRetorno["DATSUB"] := dDataBase
            oRetorno["QTDSUB"] := Val(Subs(cLinha, 20, 7))
            oRetorno["STATUS"] := "99"
        
        Case cSegmento == "06" //kits
            oRetorno["CODITE"] := UPPER(Subs(cLinha, 10, 7))
            oRetorno["QTDADE"] := Val(Subs(cLinha, 20, 7))
            oRetorno["CODKIT"] := UPPER(Subs(cLinha, 3, 7))
        
        Case cSegmento == "06" //kits
            oRetorno["CODITE"] := UPPER(Subs(cLinha, 10, 7))
            oRetorno["CODKIT"] := UPPER(Subs(cLinha, 3, 7))
            oRetorno["QTDADE"] := Val(Subs(cLinha, 20, 7))
    EndCase

Return oRetorno

/*/{Protheus.doc} OA538013J_VerificaEGravaVEH
    Vai criar ou atualizar a tabela VEH de acordo com as informações do segmento 06 do arquivo GLASS    
    Tabela cabeçalho de kits
    @type  Static Function
    @author Renan Migliaris
    @since 17/09/2025
/*/
Static Function OA538012J_VerificaEGravaVEH(oTmpTab)
    local lRet := .t.
    local lOk := .t.
    local cQuery := ''
    local aVEHFields := {}
    local oBulkVEH := FwBulk():new(RetSQLName("VEH"), 850)
    local cRealName := oTmpTab:GetTableNameForQuery()
    local cAlias := ''
    local aFils := OA538015J_VerificaAcessoExclusivo("VEH")
    local nX := 0

    aVEHFields := {;
        {"VEH_FILIAL"},; 
        {"VEH_TIPO"},;
        {"VEH_GRUKIT"},; 
        {"VEH_CODKIT"},; 
        {"VEH_DESKIT"},; 
        {"VEH_VALKIT"};
    }

    oBulkVEH:setFields(aVEHFields)

    for nx := 1 to len(aFils)
        cQuery := " SELECT "
        cQuery += "     T.CODKIT, "
        cQuery += "     T.GRUPO, "
        cQuery += "     B1.B1_DESC AS DESKIT "
        cQuery += " FROM " + cRealName + " T "
        cQuery += " LEFT JOIN " + RetSQLName("SB1") + " B1 "
        cQuery += "     ON B1.B1_CODITE = T.CODITE "
        cQuery += "     AND B1.B1_GRUPO = T.GRUPO "
        cQuery += "     AND B1.B1_COD = T.CODIGO "
        cQuery += "     AND B1.D_E_L_E_T_ = ' ' "
        cQuery += " WHERE 
        cQuery += "     T.SEGMENTO = '06' "
        cQuery += "     AND T.CODKIT <> ' ' "
        cQuery += "     AND NOT EXISTS ( "
        cQuery += "     SELECT 1 FROM "+RetSQLName("VEH")+" VEH "
        cQuery += "     WHERE VEH.VEH_FILIAL =  '"+aFils[nx]+"' "
        cQuery += "         AND VEH.VEH_CODKIT = T.CODKIT "
        cQuery += "         AND VEH.VEH_GRUKIT = T.GRUPO "
        cQuery += "         AND VEH.VEH_TIPO = '2' " //chumbado no fonte original ofia440
        cQuery += "         AND VEH.D_E_L_E_T_ = ' ' "
        cQuery += "         AND T.CODKIT <> ' ' "
        cQuery += ")"

        cAlias := GetNextAlias()

        dbUseArea(.t., "TOPCONN", TcGenQry(,,cQuery), cAlias, .f., .t.)
        while !(cAlias)->(eof())
            oBulkVEH:addData({;
                aFils[nx],; //filial
                "2",; //tipo 2 seguindo a rotina OFIIA440 ele foi chumbado lá como tipo 2 
                (cAlias)->GRUPO,; //grukit
                (cAlias)->CODKIT,; //codkit
                (cAlias)->DESKIT,; //deskit
                0; //valkit valor que foi chumbado na rotina original OFIIA440
            })

            (cAlias)->(dbSkip())
        endDo
        (cAlias)->(dbCloseArea())
        oBulkVEH:flush()
    next

    lOk := oBulkVEH:Close()
    if .not. lOk
        OA538003J_LogaExecucao(cOrigem, STR0008, OA538004J_ParametrosString(oBulkVEH:getError() + " VEH")) //Erro
    else
        OA538003J_LogaExecucao(cOrigem, STR0013, OA538004J_ParametrosString("VEH SALVA")) //Sucesso //"VEH SALVA"
        OA538013J_VerificaEGravaVE8(oTmpTab)
    endif
    oBulkVEH:destroy()
    freeObj(oBulkVEH)
    fwFreeArray(aVEHFields)
Return lRet 

/*/{Protheus.doc} OA538013J_VerificaEGravaVE8
    Função que irá verificar, gravar ou atualizar a tabela VE8
    Se o registro não existir vai pro bulk insert
    Se existir vou atualizar ele
    A VE8 é uma tabela filho da VEH
    @type  Static Function
    @author Renan Migliaris
    @since 18/09/2025
/*/
Static Function OA538013J_VerificaEGravaVE8(oTmpTab)
    local lRet := .t.
    local lOk := .t.
    local cQuery := ''
    local aVE8Fields := {}
    local oBulkVE8 := FwBulk():new(RetSQLName("VE8"), 850)
    local cRealName := oTmpTab:GetTableNameForQuery()
    local cAlias := ''
    local aFils := OA538015J_VerificaAcessoExclusivo("VE8")
    local nX := 0

    aVE8Fields := {;
        {"VE8_FILIAL"},; 
        {"VE8_TIPO"},; 
        {"VE8_GRUKIT"},; 
        {"VE8_CODKIT"},; 
        {"VE8_GRUITE"},; 
        {"VE8_CODITE"},; 
        {"VE8_QTDADE"};
    }

    oBulkVE8:setFields(aVE8Fields)

    for nx := 1 to len(aFils)
        cQuery := " SELECT "
        cQuery += "  T.CODKIT, "
        cQuery += "  T.GRUPOKIT, "
        cQuery += "  T.CODITE, "
        cQuery += "  T.QTDADE, "
        cQuery += "  T.GRUPO "
        cQuery += " FROM " + cRealName + " T "
        cQuery += " WHERE "
        cQuery += "     T.SEGMENTO = '06' "
        cQuery += "     AND T.CODKIT <> ' ' "
        cQuery += "     AND T.GRUPOKIT <> ' ' "
        cQuery += "     AND NOT EXISTS ( "
        cQuery += "     SELECT 1 FROM "+RetSQLName("VE8")+" VE8 "
        cQuery += "     WHERE VE8.VE8_FILIAL =  '"+aFils[nx]+"' "
        cQuery += "        AND VE8.VE8_GRUKIT = T.GRUPOKIT "
        cQuery += "        AND VE8.VE8_CODKIT = T.CODKIT "
        cQuery += "        AND VE8.VE8_GRUITE = T.GRUPO "
        cQuery += "        AND VE8.VE8_CODITE = T.CODITE "
        cQuery += "        AND VE8.D_E_L_E_T_ = ' ' "
        cQuery += "        AND T.CODKIT <> ' ' "
        cQuery += "        AND T.GRUPOKIT <> ' ' "
        cQuery += "        AND T.CODITE <> ' ' "
        cQuery += "        AND T.GRUPO <> ' ' "
        cQuery += " )"

        cAlias := GetNextAlias()

        dbUseArea(.t., "TOPCONN", TcGenQry(,,cQuery), cAlias, .f., .t.)
        while !(cAlias)->(eof())
            oBulkVE8:addData({;
                aFils[nx],; //filial
                "1",; //tipo 1 seguindo a rotina OFIIA440 ele foi chumbado lá como tipo 2 
                (cAlias)->GRUPOKIT,; //grukit
                (cAlias)->CODKIT,; //codkit
                (cAlias)->GRUPO,; //gruitem
                (cAlias)->CODITE,; //codite
                (cAlias)->QTDADE; //qtidade
            })

            (cAlias)->(dbSkip())
        endDo
        (cAlias)->(dbCloseArea())
        oBulkVE8:flush()
    next
    lOk := oBulkVE8:Close()
    if .not. lOk
        OA538003J_LogaExecucao(cOrigem, STR0008, OA538004J_ParametrosString(oBulkVE8:getError() + " VE8")) //Erro
    else
        OA538003J_LogaExecucao(cOrigem, STR0013, OA538004J_ParametrosString("VE8 SALVA")) //Sucesso //"VE8 SALVA"
    endif
    oBulkVE8:destroy()
    freeObj(oBulkVE8)
    fwFreeArray(aVE8Fields)
Return lRet

/*/{Protheus.doc} OA538014J_CriaTabelaTemporaria
    Função que vai criar a tabela temporária que irá armazenar os dados do arquivo glass
    A tabela temporária será destruída no final do processamento
    A partir dela que as demais "alimentações" das tabelas serão feitas
    @type  Static Function
    @author user
    @since 17/09/2025
    @version version
    @param param_name, param_type, param_descr
    @return return_var, return_type, return_description
    @example
    (examples)
    @see (links_or_references)
/*/
Static Function OA538014J_CriaTabelaTemporaria(oFile)
    local lRet := .t.
    local aBulkFie := {}
    local aFields := {}
    local cCenCus := ''
    local cDesmar := ''
    local cCtaCtb := ''
    local cGruIte := ''
    local cRealName := ''
    local nCont := 0
    local cLinha := ''
    local nLinha := 0
    local nX := 0
    local nTFabr := TamSX3("B1_FABRIC")[1]
    local oItem := nil
    local oBulk := nil
    local cNumSeq := Strzero(0,TamSX3("VE9_NROSEQ")[1])
    
    cGruIte := MV_PAR01

    DbSelectArea('VE4')
    DbSetOrder(1)
    DbSeek(xFilial('VE4'))

    if !Empty(MV_PAR02)
        cCenCus := alltrim(MV_PAR02)
    else 
        cCencus := VE4->VE4_CENCUS
    endif

    if !Empty(MV_PAR03)
        cCtaCtb := alltrim(MV_PAR03)
    else 
        cCtaCtb := VE4->VE4_CTACTB
    endif

    aadd(aFields, {"CODIGO", "C", TamSX3("B1_COD")[1], TamSX3("B1_COD")[2]})
    aadd(aFields, {"GRUPO", "C", TamSX3("B1_GRUPO")[1], TamSX3("B1_GRUPO")[2]})
    aadd(aFields, {"CODITE", "C", TamSX3("B1_CODITE")[1], TamSX3("B1_CODITE")[2]})
    aadd(aFields, {"FABRIC", "C", TamSX3("B1_FABRIC")[1], TamSX3("B1_FABRIC")[2]})
    aadd(aFields, {"DESCRIC", "C", TamSX3("B1_DESC")[1], TamSX3("B1_DESC")[2]})
    aadd(aFields, {"UM", "C", TamSX3("B1_UM")[1], TamSX3("B1_UM")[2]})
    aadd(aFields, {"SEGUM", "C", TamSX3("B1_SEGUM")[1], TamSX3("B1_SEGUM")[2]})
    aadd(aFields, {"TIPO", "C", TamSX3("B1_TIPO")[1], TamSX3("B1_TIPO")[2]})
    aadd(aFields, {"LOCPAD", "C", TamSX3("B1_LOCPAD")[1], TamSX3("B1_LOCPAD")[2]})
    aadd(aFields, {"PICM", "N", TamSX3("B1_PICM")[1], TamSX3("B1_PICM")[2]})
    aadd(aFields, {"IPI", "N", TamSX3("B1_IPI")[1], TamSX3("B1_IPI")[2]})
    aadd(aFields, {"PRV1", "N", TamSX3("B1_PRV1")[1], TamSX3("B1_PRV1")[2]})
    aadd(aFields, {"CONTA", "C", TamSX3("B1_CONTA")[1], TamSX3("B1_CONTA")[2]})
    aadd(aFields, {"CENTRO", "C", TamSX3("B1_CC")[1], TamSX3("B1_CC")[2]})
    aadd(aFields, {"PESO", "N", TamSX3("B1_PESO")[1], TamSX3("B1_PESO")[2]})
    aadd(aFields, {"TIPOCQ", "C", TamSX3("B1_TIPOCQ")[1], TamSX3("B1_TIPOCQ")[2]})
    aadd(aFields, {"ORIGEM", "C", TamSX3("B1_ORIGEM")[1], TamSX3("B1_ORIGEM")[2]})
    aadd(aFields, {"CLASFIS", "C", TamSX3("B1_CLASFIS")[1], TamSX3("B1_CLASFIS")[2]})
    aadd(aFields, {"SEQVE9", "C", TamSX3("VE9_NROSEQ")[1], TamSX3("VE9_NROSEQ")[2]})
    aadd(aFields, {"NROSUBVE9", "C", TamSX3("VE9_NROSUB")[1], TamSX3("VE9_NROSUB")[2]})
    aadd(aFields, {"ITENOV", "C", TamSX3("VE9_ITENOV")[1], TamSX3("VE9_ITENOV")[2]})
    aadd(aFields, {"ITEANT", "C", TamSX3("VE9_ITEANT")[1], TamSX3("VE9_ITEANT")[2]})
    aadd(aFields, {"STAGLA", "C", TamSX3("VE9_STAGLA")[1], TamSX3("VE9_STAGLA")[2]})
    aadd(aFields, {"APLICA", "C", TamSX3("VE9_APLICA")[1], TamSX3("VE9_APLICA")[2]})
    aadd(aFields, {"QTDADE", "N", TamSX3("VE9_QTDADE")[1], TamSX3("VE9_QTDADE")[2]})
    aadd(aFields, {"DATSUB", "D", TamSX3("VE9_DATSUB")[1], TamSX3("VE9_DATSUB")[2]})
    aadd(aFields, {"QTDSUB", "N", TamSX3("VE9_QTDSUB")[1], TamSX3("VE9_QTDSUB")[2]})
    aadd(aFields, {"STATUS", "C", TamSX3("VE9_STATUS")[1], TamSX3("VE9_STATUS")[2]})
    aadd(aFields, {"SEGMENTO", "C", TamSX3("VE9_SEGMEN")[1], TamSX3("VE9_SEGMEN")[2]})
    aadd(aFields, {"CODKIT", "C", TamSx3("VE8_CODKIT")[1], TamSX3("VE8_CODKIT")[2]})
    aadd(aFields, {"GRUPOKIT", "C", TamSx3("VE8_GRUKIT")[1], TamSX3("VE8_GRUKIT")[2]})

    cAliasTmp := GetNextAlias()
    oTmpTab := FWTemporaryTable():new(cAliasTmp) 
    oTmpTab:setFields(aFields)
    oTmpTab:addIndex("1", {"CODIGO"})

    for nX := 1 to len(aFields)
        aadd(aBulkFie, {aFields[nx][1]})
    next

    oTmpTab:Create() 

    DbSelectArea("VE1")
    DbSetOrder(1)
    DbSeek(xFilial("VE1") + VE4->VE4_PREFAB)

    cDesmar := Left(VE1->VE1_DESMAR, nTFabr)

    cRealName := oTmpTab:GetTableNameForTCFunctions() //função para pegar o nome para ser usada em outras funções do DBAccess
    
    
    oBulk := FwBulk():new(cRealName)
    oBulk:setFields(aBulkFie)

    while oFile:hasLine()
        nCont++
        cNumSeq := soma1(cNumSeq)
        cLinha := oFile:GetLine()
        oItem := OA538011J_MontaItemDeAcordoComOSeguimento(cLinha)
        if Left(cLinha,2) == "01" .or. Left(cLinha,2) == "04" .or. Left(cLinha,2) == "06" .or. Left(cLinha,2) == "02"
            oBulk:addData({;
                oItem["CODIGO"],;                              // CODIGO
                cGruIte,;                                      // GRUPO
                oItem["CODITE"],;                              // CODITE
                cDesmar,;                                      // FABRIC
                oItem["DESCRICAO"],;                           // DESCRIC
                "PC",;                                         // UM
                "PC",;                                         // SEGUM
                "ME",;                                         // TIPO
                alltrim(MV_PAR04),;                            // LOCPAD
                0,;                                            // PICM 
                0,;                                            // IPI 
                0,;                                            // PRV1 
                cCtaCtb,;                                      // CONTA
                cCenCus,;                                      // CENTRO
                1,;                                            // PESO 
                "M",;                                          // TIPOCQ 
                "0",;                                          // ORIGEM 
                "00",;                                         // CLASFIS 
                cNumSeq,;                                      // SEQVE9
                Strzero(nCont,TamSX3("VE9_NROSUB")[1]),;       // NROSUBVE9 //Soma1 com tamanho 6
                oItem["ITENOV"],;                              // ITENOV
                oItem["ITEANT"],;                              // ITEANT
                oItem["STAGLA"],;                              // STAGLA
                oItem["APLICA"],;                              // APLICA 
                oItem["QTDADE"],;                              // QTDADE
                oItem["DATSUB"],;                              // DATSUB
                oItem["QTDSUB"],;                              // QTDSUB
                oItem["STATUS"],;                              // STATUS
                oItem["SEGMENTO"],;                            // SEGMENTO
                oItem["CODKIT"],;                              // CODKIT
                cGruIte;                                       // GRUPOKIT
            })
        endif
        nLinha++
    endDo
    oBulk:flush()
    oBulk:Close()
    oBulk:destroy()
    
    fwFreeArray(aFields)
    fwFreeArray(aBulkFie)
    freeObj(oBulk)
Return lRet

/*/{Protheus.doc} OA538015J_VerificaAcessoExclusivo
    Vai verificar se o acesso é exclusivo.
    Se o acesso for compartilhado vai retornar um array de filiais com o xFilial do alias recebido
    Caso contrário a função que chamar aqui vai usar a private aFilAux
    @type  Static Function
    @author Renan Migliaris
    @since 18/09/2025
/*/
Static Function OA538015J_VerificaAcessoExclusivo(cAlias)
    local aRet := {}

    if FWModeAccess(cAlias, 3) == "E"
        aRet := aClone(aFilAux)
    else
        aRet := {xFilial(cAlias)} 
    endif

Return aRet


/*/{Protheus.doc} OA538016J
    Valida o grupo da peça informado no parâmetro MV_PAR01
    @type  Function
    @author Renan Migliaris
    @since 19/09/2025
    /*/
Function OA538016J()
    local lRet := .t.
    DbSelectArea("SBM")
    DbSetOrder(1)
    
    if !Empty(MV_PAR01) .and. (DbSeek(xFilial("SBM") + MV_PAR01))
        lRet := .t.
    else
        FMX_HELP(STR0005, STR0026) //OFIA538 //"Grupo Padrão da Peça Inválido"
        lRet := .f.
    endif
    dbCloseArea()
Return lRet

/*/{Protheus.doc} OA538016J
    Valida o MV_PAR02 Conta Padrão
    @type  Function
    @author Renan Migliaris
    @since 19/09/2025
    /*/
Function OA538017J()
    local lRet := .t.
    DbSelectArea("CT1")
    DbSetOrder(1)
    if !Empty(MV_PAR02)
        If !DbSeek(xFilial("CT1") + MV_PAR02)
            FMX_HELP(STR0005, STR0025) //"OFIA538" //"Conta Contábil Padrão da Peça Inválida"
            lRet := .f.
        EndIf
    endif
    dbCloseArea()
Return lRet

/*/{Protheus.doc} OA538017J
    Valida o MV_PAR03 CTT
    @type  Function
    @author Renan Migliaris
    @since 19/09/2025
    /*/
Function OA538018J()
    local lRet := .t. 
    DbSelectArea("CTT")
    DbSetOrder(1)

    if !Empty(MV_PAR03)
        If !DbSeek(xFilial("CTT") + MV_PAR03)
            FMX_HELP(STR0005, STR0024) //"OFIA538" //"Centro de Custo Padrão da Peça Inválido"
            lRet := .f.
        EndIf
    endif
    dbCloseArea()
Return lRet


/*/{Protheus.doc} OA538018J
    Valida o MV_PAR04 Localização Padrão
    @type  Function
    @author Renan Migliaris
    @since 19/09/2025
    /*/
Function OA538019J()
    local lRet := .t.
    DbSelectArea("NNR")
    DbSetOrder(1)
    
    if !Empty(MV_PAR04) .and. (DbSeek(xFilial("NNR") + MV_PAR04))
        lRet := .t.
    else
        FMX_HELP(STR0005, STR0023) //"OFIA538" //"Localização Padrão da Peça Inválida"
        lRet := .f.
    endif
    dbCloseArea()
Return lRet

/*/{Protheus.doc} OA538020J_SetaFieldsBulk
    Verifica os arrays de fields que podem vir ou não do ponto de entrada
    Seta o bulk da maneira correta com o array certo 
    Manipula o objeto pra fazer esse insert bulk 
    @type  Static Function
    @author Renan Migliaris
    @since 26/09/2025
/*/
Static Function OA538020J_SetaFieldsBulk(oBulk, aFields, aFielAux)
    local nX := 0

    if (valtype(aFielAux) == "A") .and. (len(aFielAux) > 0)
        for nx := 1 to len(aFielAux)
            aadd(aFields, aFielAux[nx])
        next
    endif

    oBulk:setFields(aFields)
Return

/*/{Protheus.doc} OA538021J_SetaODadoDoItem
    Mesma coisa da setaField só que com o dado do item
    @type  Static Function
    @author Renan Migliaris
    @since 26/09/2025
/*/
Static Function OA538021J_SetaODadoDoItem(oBulk, aDado, aNewDado)
    if (valtype(aNewDado) == "A") .and. len(aNewDado) > 0
        oBulk:addData(aNewDado[1])
    else
        oBulk:addData(aDado[1])
    endif
Return


/*/{Protheus.doc} OA538022J_ValidaSelecaoDeArquivosPergunte
    Valida a seleção dos arquivos
	@type Function
	@author Renan Migliaris
	@since 17/10/2025
/*/
Function OA538022J_ValidPerg()

	Local lRet 		:= .T.

    if ReadVar() == 'MV_PAR07' .and. MV_PAR06 == 2
        MV_PAR07 := cGetFile(STR0030, STR0031, , "SERVIDOR", .T., GETF_RETDIRECTORY, .T., .T. ) //"Diretório" //"Glass-Scania"
    endif

Return lRet
/*/{Protheus.doc} schedDef
    Função padrão scheduler
    @type  Static Function
    @author Renan Migliaris
    @since 22/08/2025
/*/
Static Function schedDef()
    local aParam := {;
        "P",;
        "OFIA538",;
        "",;
        "",;
        "";
    }
Return aParam
  • Tamanho do arquivo .DAT: 
  • Quantidade de peças contidos no arquivo: 
  • Tempo de processamento do arquivo pela rotina: 

Para que a importação de serviços ocorra corretamente durante o processamento do arquivo XML, é necessário que na rotina Grupos de Serviço (OFIOA020), existam registros cadastrados com o campo “Cod. Grp Mont” devidamente preenchido, conforme os códigos pré-definidos pela montadora Scania.

Essa configuração garante o correto mapeamento entre os grupos de serviço da Scania e os grupos cadastrados no Protheus, permitindo que o sistema identifique e vincule corretamente os serviços durante o processo de importação.



00    Generalidades
01    Motor
02    Sistema de arrefecimento
03    Sistemas de escape/combustível
04    Embreagem
05    Caixa de mudanças
06    Árvore de transmissão
07    Eixo dianteiro
08    Eixo traseiro
09    Cubo e rodas
10    Freios
11    Chassi
12    Suspensão
13    Direção
14    Controle do motor
16    Sistema elétrico
17    Instrumentos
18    Cabina
19    Equipamento complementar
20    Carroceria de carga
21    Reboque
43    Carroceria de ônibus Irizar

Essas informações são de responsabilidade dos concessionários e deverão ser obtidas junto à Montadora Scania.


Criação de Campo no arquivo SX3 – Campos:


  • Tabela VOS - Grupos de Serviços


CampoVOS_GRPSER
TipoCaractere
Grupo de Campos
Ordem09
Tamanho2
Decimal0
Formato@!
Contexto1-Real
Propriedade1-Alterar
TítuloCod Grp Mont
DescriçãoCod Grp Servico Montadora
Val. SistemaOA0200018_VldGrp()
Opções
Inic. Padrão
Inic. Browse
Cons. Padrão
Nível1
UsadoSim
ObrigatórioNão
BrowseNão
When
Pasta
Help

Grupo de servico da Montadora




  • No Configurador (SIGACFG), acesse Ambientes/Cadastros/Menu (CFGX013) e informe as novas opções de menu do módulo de Oficina (SIGAOFI) conforme instruções a seguir:


Menu

Atualizações

Submenu

Cadastros Oficina

Nome da Rotina

Importação Glass

Programa

OFIA538

Módulo

Oficina (SIGAOFI)

Tipo

Função Protheus



Criação de Pergunte no arquivo SX1 – Pergunta


Grupo

OFIA533OFIA533OFIA533OFIA533OFIA533

Ordem

0102030405

Pergunta

Marca ?Arquivo XML ?Quantidade Mecânicos ?Ação pós Processamento ?Mover Para ?

Tipo

CCNCC
Tamanho3991199
Decimal00000
Var01MV_PAR01MV_PAR02MV_PAR03MV_PAR04MV_PAR05
Formato

@E 9

ValidaçãoExistCpo("VE1",MV_PAR01)OA533002K_ValidPerg()!Vazio() .AND. (MV_PAR03 >= 1 .And. MV_PAR03 <= 9)NaoVazio()OA533002K_ValidPerg()
ObjetoGetGetGetComboGet
Consulta PadrãoVE1



Pré-Seleção (Combo)


1
Item 1


Nenhuma Ação
Item 2


Mover Arquivo
Item 3


Apagar Arquivo
Item 4




Item 5




Help











4. Fluxo de Utilização


  1. Acesse o Módulo 14 (Oficina).
  2. Acesse o menu Atualizações → Cadastros Oficina → Importação Glass (OFIA538).
  3. Preencha os parâmetros obrigatórios:
    • Grupo Padrão da Peça
    • Armazém Padrão
    • Seleção de arquivo .DAT 
    • Ação pós Processamento
  4. No parâmetro Arquivo .DAT, será exibida uma tela mostrando o servidor (pasta protheus_data) e seus diretórios. Selecione o arquivo .DAT que será processado pela rotina.
  5. No parâmetro Ação pós Processamento:
    • Selecione a opção Nenhuma Ação. Com isso, o arquivo .DAT permanecerá no diretório original e sem ser movido ou apagado após seu processamento.
  6. Após preencher todos os parâmetros obrigatórios, clique no botão “OK”.

    • A rotina processará o arquivo .DAT e após a inclusão ou atualização de cada serviço serão executadas ações personalizadas definidas através do ponto de entrada.

    • Ao final do processamento, quando o arquivo for processado com sucesso, serão executadas ações personalizadas definidas através do ponto de entrada de conclusão da rotina.



     


  1. Acesse o Módulo 14 (Oficina).
  2. Acesse o menu Atualizações → Cadastros Oficina → Importação Scania (OFIA538).
  3. Preencha os parâmetros obrigatórios:
    • Grupo Padrão da Peça
    • Armazém Padrão 
    • Seleção do arquivo .DAT
    • Ação pós Processamento
  4. No parâmetro Arquivo .DAT, será exibida uma tela mostrando o servidor (pasta protheus_data) e seus diretórios. Selecione o arquivo .DAT que será processado pela rotina.
  5. No parâmetro Ação pós Processamento:
    • Selecione a opção Mover Arquivo. Com isso, o parâmetro Mover Para será habilitado, permitindo que seja selecionado o diretório de destino dentro do servidor. Ao final do processamento, o arquivo será movido do diretório de origem para o diretório selecionado.
  6. Após preencher todos os parâmetros obrigatórios, clique no botão “OK”.

    • A rotina processará o arquivo .DAT e após a inclusão ou atualização das peças serão executadas ações personalizadas definidas através do ponto de entrada.

    • Ao final do processamento, quando o arquivo for processado com sucesso, serão executadas ações personalizadas definidas através do ponto de entrada de conclusão da rotina, e o arquivo será movido do diretório original para o diretório destino indicado no parâmetro Mover Para.



  1. Acesse o Módulo 14 (Oficina).
  2. Acesse o menu Atualizações → Cadastros Oficina → Importação de Serviços Scania (OFIA533).
  3. Preencha os parâmetros obrigatórios:
    • Marca
    • Arquivo XML
    • Quantidade Mecânicos 
    • Ação pós Processamento
  4. No parâmetro Arquivo XML, será exibida uma tela mostrando o servidor (pasta protheus_data) e seus diretórios. Selecione o arquivo XML que será processado pela rotina.
  5. No parâmetro Ação pós Processamento:
    • Selecione a opção Apagar Arquivo. Com isso, ao término do processamento do arquivo, ele será apagado do diretório de onde foi selecionado.
  6. Após preencher todos os parâmetros obrigatórios, clique no botão “OK”.

    • A rotina processará o arquivo XML e após a inclusão ou atualização de cada serviço serão executadas ações personalizadas definidas através do ponto de entrada.

    • Ao final do processamento, quando o arquivo for processado com sucesso, serão executadas ações personalizadas definidas através do ponto de entrada de conclusão da rotina, e o arquivo será apagado do diretório original onde foi selecionado.



Após a execução da rotina, será possível visualizar na tabela VQL (Informacoes genericas) os registros de log do processamento, conforme o exemplo apresentado na imagem abaixo.

  • Na coluna VQL_AGROUP (Agrupador), será registrado o nome do fonte da rotina;
  • Na coluna VQL_TIPO (Tipo), será registrado o local de execução da rotina, podendo ser via Menu ou Schedule;
  • Na coluna VQL_MSGLOG (Mensagens de Log), será registrada a mensagem de log referente ao status de execução da rotina (Início, Processamento, Finalização ou Erro).




5. Integrações e Dependências


Integração

Para o correto funcionamento da rotina, durante a execução da Importação de Serviços Scania (OFIA533) ocorre a integração com a rotina Tabela de Serviços (OFIOA030).
Após o processamento bem-sucedido do arquivo XML, os serviços contidos no arquivo são cadastrados na Tabela de Serviços caso ainda não existam, ou terão o campo "Tmpo Fábrica" (VO6_TEMFAB) atualizado, caso já estejam registrados.
Essa integração garante que os dados enviados pela montadora Scania sejam incorporados ao Protheus, mantendo o cadastro de serviços sempre atualizado e alinhado às informações da montadora.



6. Assuntos Relacionados


<style>
  .link_container {
    display: flex;
    flex-direction: column;
    align-items: flex-start; /* Alinhado à esquerda */
    width: 100%;
    gap: 8px; /* Espaçamento entre os itens */
  }

  .btn-doc,
  .btn-doc:link,
  .btn-doc:visited {
    display: inline-block;
    padding: 12px 24px;
    font-size: 16px;
    font-weight: 600;
    color: #FFFFFF !important; /* Força o texto branco */
    background-color: #08244C; /* Fundo azul escuro */
    border: none;
    border-radius: 8px;
    text-decoration: none;
    text-align: left;
    transition: background-color 0.3s ease, transform 0.2s ease, color 0.3s ease;
  }

  .btn-doc:hover {
    background-color: #FFFFFF; /* Azul mais claro no hover */
    color: #08244C !important; /* Mantém texto branco */
    transform: scale(1.03);
  }

  .btn-doc:active {
    background-color: #061B3B; /* Azul ainda mais escuro no clique */
    color: #FFFFFF !important; /* Mantém texto branco */
    transform: scale(0.98);
  }
</style>

<div class="link_container">
  <a href="https://tdn.totvs.com/pages/viewpage.action?pageId=973046863" target="_blank" class="btn-doc">     
	📄 Novo campo Cod Grp Servico Montadora - Grupos de Serviço (OFIOA020)
  </a>
  <a href="https://tdn.totvs.com/pages/viewpage.action?pageId=1008697602" target="_blank" class="btn-doc">     		
	📄 Ponto de Entrada OF533SER - Importação de Serviços Scania (OFIA533)   
  </a>
  <a href="https://tdn.totvs.com/pages/viewpage.action?pageId=1008699858" target="_blank" class="btn-doc">     
	📄 Ponto de Entrada OF533FIM - Importação de Serviços Scania (OFIA533)   
  </a>
</div>