Árvore de páginas

Versões comparadas

Chave

  • Esta linha foi adicionada.
  • Esta linha foi removida.
  • A formatação mudou.

...

Índice
minLevel0
include[Identificação da Rotina]
indent10px


...

1. Identificação da Rotina


Nome da Rotina

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

11

 


...

2. Descrição Funcional

A rotina Importação GLASS (OFIA538) tem como finalidade facilitar objetivo simplificar a importação e atualização das peças enviadas pela montadora Scania para o sistema Protheus DMS, a partir de um do 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.

) (.DAT) fornecido pela montadora. Esse arquivo reúne informações de peças, substituições e kits.

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

Após as validaçõesa validação dos parâmetros, o sistema interpreta o conteúdo do arquivo GLASS e executa o processamento de realiza a inclusão ou atualização das peças , de acordo com conforme as informações oficiais enviadas pela da Scania.

Concluída a importaçãoFinalizado o processamento, o sistema executa as ações de pós-processamento configuradas, que podem incluir,  definidas na configuração, como manter, mover ou apagar excluir o arquivo, e gera além de gerar logs detalhados com o resultado detalhamento da operação.

Dessa formaAssim, a rotina OFIA538 auxilia na Importação GLASS (OFIA538) contribui para a organização e manutenção do cadastro de peças da Scania dentro do no 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 oficiaisdisponibilizadas pela Scania. e substituindo a rotina OFIIA440, que possuía parâmetros fixos e menor desempenho em arquivos de grande volume, parametrizável e alinhado às informações oficiais da montadora.


...

3. Pré-requisitos e Configurações


Totvs custom tabs box
tabsPré-requisitos, Configurações, Atualização de Dicionário/Menu
idsaba1,aba2,aba3
Totvs custom tabs box items
defaultyes
referenciaaba1

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
  1. no menu do Protheus, permitindo assim o acesso à funcionalidade.
  2. Deve-se possuir um arquivo com a extensão .DAT
 
  1. contendo as peças enviadas pela montadora Scania, que será utilizado como base para o processo de importação.
referencia
Totvs custom tabs box items
defaultyes
aba1


**

delphi
Bloco de código
language
themeRDark
titleOFIA538 (Advpl)Exemplo arquivo DAT
010000001PECA TESTE     #include "Protheus.ch"
#include 'TOPCONN.ch'
#include 'OFIA538.ch'

/*/{Protheus.doc} OFIA538
    GLASS - SCANIA
    @type  Function
   TESTE @author Renan Migliaris
    @since 20/08/2025
  ITEM SUBSTITUIDO /*/
Function OFIA538()
    local aArea := FwGetArea()
    local lRetARTICULO := .f.
REEMPLAZADO     local lFunc := .t.
  REPLACED ITEM private lPePro := ExistBlock("OF538PRO")
    private lPeFim := ExistBlock("OF538FIM")
    private lSched := FWGetRunSchedule()
 000010000001N0000560PECA TESTE  private cOrigem := ""
    private cPerg := "OFIA538"
    private lPEnt := ExistBlock("IA440DPG") //questão da chamada de ponto de entrada99
0400000013170991   0000001  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()
  99
010001200TESTE - TESTE TESTE           TESTE          ITEM DESATIVADO               FWMsgRun(,{|| OA538002J_ProcessaArquivo(@lFUnc), STR0004})
ARTICULO DESATIVADO           DEACTIVED ITEM     if lFunc
            109400000001I0001530TESTE - TESTE TESTE     FWAlertSuccess(STR0005, STR0006) //'OFIA538' //'Arquivo Processado Com Sucesso!'
     99
0400012000811288   0000001            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.
   99
010001400TESTE-TESTE TESTE             TESTE        endif
   ITEM SUBSTITUIDO              ARTICULO REEMPLAZADO    Exit
      REPLACED ITEM     end
        endDo
    else
  109400000001I0000500TESTE TESTE - TESTE   if OA538001J_VerificaPerguntePreenchido()
            OA538002J_ProcessaArquivo(@lFunc)
99
020001400TESTE            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)))
99
020001400LK140     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))
  99
0400014000811285   0000001       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])
          99
010001683PECA TESTE next
                   TESTE    FMX_HELP(STR0008, STR0022 + alltrim(cMsg)) //"Erro" //"Os seguintes parâmetros não foram preenchidos corretamente: "
          ITEM DESCONTINUADO            ARTICULO DESCONTINUADO     endif
   DESCONTINUED     lRet := .f.
    endif

Return lRet

/*/{Protheus.doc} OA538002J_ProcessaArquivo()
    Realiza o processamento do199100000001I0004030TESTE arquivo .Dat enviado
    @type  Static Function
    @author Renan Migliaris
    @since 21/08/2025
/*/
Static Function OA538002J_ProcessaArquivo(lRet)
    local cFile := alltrim(MV_PAR05)
 99
020001683TESTE.T     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
      99
010001719TESTE      Case  nAcaoArq  ==  2
             TESTE          cDestITEM := alltrim(lower(alltrim(MV_PAR07)+ "\" + SubStr(cFile, Rat("\", cFile) + 1)))
DESCONTINUADO            ARTICULO DESCONTINUADO        DESCONTINUEDD   lCopy := __CopyFile(cArqOrig, alltrim(lower(cDest)))
             019990000001I0000000TESTE   if lCopy
                    oFile:erase()
      99
020001719TESTE.T          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()
99
010001721TESTE(TESTE)                  defaultTESTE lHorFin  := .f.

       ITEM 
DESCONTINUADO    aadd(adata, {"VQL_AGROUP", "OFIA538"})
    aadd(adata, {"VQL_FILORI", cFilAnt})
  ARTICULO DESCONTINUADO   aadd(adata, {"VQL_TIPO", cTipo})
   DESCONTINUED aadd(adata, {"VQL_MSGLOG", cMensagem})
    aadd(adata, {"VQL_DADOS", cOrigem})
    if lHorFin
      019660000001I0000000TESTE(TESTE)  aadd(aData, {"VQL_HORAF", VAL(STRTRAN(SUBSTR( TIME() , 1, 5), ":", "" ))})
                   aadd(adata, {"VQL_DATAF", dDataBase})
 99
020001721TESTE.T       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
99
010001722TESTE                      endif

   TESTE cParams  := oParams:toJson()

         freeObj(oParams)
Return cParams

/*/{Protheus.doc} OA538005J_PreparaVE9
ITEM DESCONTINUADO      Função que irá realizar a preparação daARTICULO VE9DESCONTINUADO para uma nova importação
    @typeDESCONTINUED  Static Function
    @author Renan Migliaris
    @since 25/08/2025    
/*/
Static Function OA538005J_PreparaVE9()
  199010000001N0000000TESTE TESTE   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
Nota
titleInformativo
  • Tamanho do arquivo .DAT: 
  • Quantidade de peças contidos no arquivo: 
  • Tempo de processamento do arquivo pela rotina: 
99
Nota
titleInformativo
  • Tamanho do arquivo .DAT: Aproximadamente 224 MB*.
  • Quantidade de peças contidas no arquivo: Aproximadamente 1 270 588 peças*.
  • Tempo de processamento do arquivo pela rotina: Aproximadamente 30 minutos*.


*Essas informações podem variar de acordo com o arquivo e a quantidade de filiais.

Totvs custom tabs box items
defaultno
referenciaaba2

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

  • Tabela VE9 - Substituição de Itens


CampoVE9_SEGMENVE9_STAGLAVE9_APLICAVE9_STATUS
TipoCaractereCaractereCaractereCaractere
Grupo de Campos



Ordem16171819
Tamanho230352
Decimal0000
Formato@!@!@!@!
Contexto1-Real  1-Real  1-Real  1-Real  
Propriedade1-Alterar1-Alterar1-Alterar1-Alterar
TítuloSegmento RegStatus GlassAplica ItemStatus
DescriçãoSegmento do registroDescrição Status GlassAplicação do ItemStatus
Val. SistemaPertence("01/02/03/04/05/06")


Opções



Inic. Padrão



Inic. Browse



Cons. Padrão




Nível



UsadoSimSimSimSim
ObrigatórioNãoNãoNãoNão
Browse



When



Pasta



Help

Campo utilizado para indicar o tipo de informação vinculada ao item, permitindo ao sistema classificar e tratar corretamente o registro.

Opções:

01 Informação Básica do Item

02 Informação Utilização do Item

03 Observação do Item

04 Informação Substituição do Item

05 Observação da Substituição do Item

06 Informação Composição do Kit

Indica a descrição do status do item importado do arquivo Glass, exclusivo da montadora Scania.

Informa os dados de utilização do item, exclusivos da montadora Scania.

Indica o status do item importado do arquivo Glass, exclusivo da montadora Scania.


  • 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 Peças

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

OFIA538OFIA538OFIA538OFIA538

Grupo de Campo

162003004024

Ordem

01020304

Pergunta

Grupo Padrão Da PeçaConta Contábil Padrão PeçaCentro De Custo Padrão PeçaArmazém Padrão da Peça

Tipo

CCNC
Tamanho22022
Decimal0000
Var01MV_PAR01MV_PAR02MV_PAR03MV_PAR04
Formato



ValidaçãoOA538016J()OA538017J()OA538018J()OA538019J()
ObjetoGetGetGetGet
Consulta PadrãoSBMCT1CTTNNR
Pré-Seleção (Combo)000
Item 1



Item 2



Item 3



Item 4



Item 5



Help



Grupo

OFIA538OFIA538OFIA538

Grupo de Campo




Ordem

050607

Pergunta

Arquivo .DATAção Após o ProcessamentoMover Para

Tipo

CC

C

Tamanho99150
Decimal000
Var01MV_PAR05MV_PAR06MV_PAR07
Formato


Validação

OA538022J_ValidPerg()
ObjetoFileComboGet
Consulta Padrão


Pré-Seleção (Combo)000
Item 1
Nenhuma Ação
Item 2
Mover Arquivo
Item 3
Apagar Arquivo
Item 4


Item 5


Help





...

4. Fluxo de Utilização


Totvs custom tabs box
tabsPasso a passo: Ação pós Processamento - Nenhuma Ação, Passo a passo: Ação pós Processamento - Mover Arquivo, Passo a passo: Ação pós Processamento - Apagar Arquivo, Gravação de Logs
idspasso1,passo2,passo3,passo4

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.


Totvs custom tabs box items
defaultyes
referenciapasso1
  1. Acesse o Módulo 14 (Oficina).
  2. Acesse o menu Atualizações → Cadastros Peças → Importação Glass (OFIA538).
  3. Preencha os parâmetros obrigatórios:
    • Grupo Padrão da Peça
    • Armazém Padrão da Peça
    • Arquivo .DAT 
    • Ação Após o 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 Após o Processamento:
    • Selecione a opção Nenhuma Ação. Com isso, o arquivo .DAT permanecerá no diretório originalsem ser movido ou apagado após o 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 das peças serão executadas ações personalizadas definidas através do ponto de entrada.

    • Ao final do processamento, serão executadas ações personalizadas definidas através dos pontos de entrada de conclusão da rotina.

Image Added

Totvs custom tabs box items
defaultno
referenciaaba2
Dica
titleExemplos de códigos de Grupos de Serviço montadora Scania
Informações
titleAviso

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

  • Tabela VOS - Grupos de Serviços
  • 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:

Criação de Pergunte no arquivo SX1 – Pergunta

Totvs custom tabs box items
defaultno
referenciaaba3
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çõesInic. PadrãoInic. BrowseCons. Padrão
Nível1
UsadoSim
ObrigatórioNão
BrowseNão
WhenPasta
Help

Grupo de servico da Montadora

Menu

Atualizações

Submenu

Cadastros Oficina

Nome da Rotina

Importação Glass

Programa

OFIA538

Módulo

Oficina (SIGAOFI)

Tipo

Função Protheus

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ãoVE1Pré-Seleção (Combo)1Item 1Nenhuma AçãoItem 2Mover ArquivoItem 3Apagar ArquivoItem 4Item 5Help

4. Fluxo de Utilização

...

tabsPasso a passo: Ação pós Processamento - Nenhuma Ação, Passo a passo: Ação pós Processamento - Mover Arquivo, Passo a passo: Ação pós Processamento - Apagar Arquivo, Gravação de Logs
idspasso1,passo2,passo3,passo4

...

defaultyes
referenciapasso1
  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.

     

Multimedia
nameImportação XML Nenhuma Ação.mp4
width1400
autostarttrue
height700

...

defaultno
referenciapasso2
  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.

Multimedia
nameImportação Arquivo XML Mover Arquivo.mp4
width1400
autostarttrue
height700

...

defaultno
referenciapasso3
passo2
  1. Acesse o Módulo 14 (Oficina).
  2. Acesse o menu Atualizações → Cadastros Peças → Importação Glass (OFIA538).
  3. Preencha os parâmetros obrigatórios:
    • Grupo Padrão da Peça
    • Armazém Padrão da Peça 
    • Arquivo .DAT
    • Ação Após o 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 Após o Processamento:
    • Selecione a opção Mover Arquivo. Com isso, o parâmetro Mover Para será habilitado, permitindo que seja selecionado o diretório destino no 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, 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.


Image Added


Totvs custom tabs box items
defaultno
referenciapasso3
  1. Acesse o Módulo 14 (Oficina).
  2. Acesse o menu Atualizações → Cadastros Peças → Importação Glass (OFIA538).
  3. Preencha os parâmetros obrigatórios:
    • Grupo Padrão da Peça
    • Armazém Padrão da Peça
    • Arquivo .DAT 
    • Ação Após o 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 Apagar Arquivo. Com isso, ao término do processamento, o arquivo será apagado do diretório onde foi 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, 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.


Image Added

Totvs custom tabs box items
defaultno
referenciapasso4

Após a execução da rotina, será possível visualizar na tabela VQL os registros de logs gerados pelo processamento, conforme o exemplo na imagem abaixo.

  • Na coluna VQL_AGROUP (Agrupador), será registrado o nome do fonte da rotina;
  • Na coluna VQL_TIPO (Tipo), será registrado o status da ação após o processamento, se houve sucesso, erro e também o início da ação.
  • 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).


Image Added


...

5. Integrações e Dependências


Integrações

Ao final da execução, as peças importadas pela rotina Importação Glass (OFIA538) estarão disponíveis nas rotinas de Cadastro de Peças (MATA010), Peças Substituídas (OFIPA910) e Kits (OFIPA920).


Principais campos importados após o processamento do arquivo DAT
Cadastro de PeçasSubstituição de ItensCadastro de Kits
Tabela SB1(Segmento 01)Tabela SB5Tabela SBZTabela VE9Tabela VEH(Cabeçalho)Tabela VE8(Itens do Kit)
B1_DATCADB5_CODBZ_CODTodos SegmentosSegmento 01Segmento 02Segmento 04Segmento 06Segmento 06
B1_CODB5_CEMEBZ_LOCPADVE9_FILIALVE9_STAGLAVE9_APLICAVE9_ITENOVVE9_ITENOVVEH_FILIALVE8_FILIAL
B1_GRUPOB5_UMIND
VE9_SEGMENVE9_ITENOVVE9_ITENOVVE9_QTDADEVE9_QTDADEVEH_TIPO  VE8_TIPO  
B1_CODITE

VE9_NROSEQ

VE9_DATSUB
VEH_GRUKITVE8_GRUKIT
B1_FABRIC

VE9_NROSUB

VE9_QTDSUB
VEH_CODKITVE8_CODKIT
B1_DESC

VE9_GRUITE

VE9_STATUS
VEH_DESKITVE8_GRUITE
B1_UM

VE9_GRUNOV



VEH_VALKITVE8_CODITE
B1_SEGUM

VE9_ITEANT




VE8_QTDADE
B1_TIPO








B1_LOCPAD








B1_CONTA








B1_CC









...

6. Assuntos Relacionados

HTML
<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=1014654380" target="_blank" class="btn-doc">     		
	📄 Ponto de Entrada OF538PRO - Importação Glass (OFIA538)   
  </a>
  <a href="https://tdn.totvs.com/pages/viewpage.action?pageId=1014655032" target="_blank" class="btn-doc">     
	📄 Ponto de Entrada OF538FIM - Importação Glass (OFIA538)   
  </a>
</div>
  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.

Multimedia
nameImportação Arquivo XML Apagar Arquivo.mp4
width1400
autostarttrue
height700

...

defaultno
referenciapasso4

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).

Image Removed

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

html