Função que cria complementos do produto (SB5) através do cadastro de produtos (SB1)

Olá pessoal…

Hoje vou mostrar uma função que criei que cria automaticamente os complementos de produto através dos produtos já cadastros.

AdvPL

AdvPL

Se você utiliza ou habilitou o complemento de produtos (tabela SB5), se já possui produtos cadastrados, já percebeu que é oneroso ter que cadastrar todos novamente, certo?

Pensando nisso, preparei um código fonte, que percorre todos os produtos criados e os que não tiverem complemento, é criado automaticamente.

Segue abaixo o código:

//Bibliotecas
#Include "Protheus.ch"
 
/*/{Protheus.doc} zSB1Compl
Função que gera o complemento do produto (SB5) através do produto (SB1)
@author Atilio
@since 29/08/2017
@version 1.0
@type function
@obs Executar como Administrador
/*/
 
User Function zSB1Compl()
    Processa({|| fProcessa()}, "Processando...")
Return
 
/*----------------------------------------------------------*
 | Func.: fProcessa                                         |
 | Desc.: Função de processamento para gravar o complemento |
 *----------------------------------------------------------*/
 
Static Function fProcessa()
    Local aArea  := GetArea()
    Local nAtual := 0
    Local nTotal := 0
    Local nOk    := 0
    Local cOk    := ""
    Local cMsg   := ""
    Local lPosUM := ( SB5->(FieldPos('B5_UMIND')) != 0)
     
    //Abre o cadastro de produtos
    DbSelectArea('SB1')
    SB1->(DbSetOrder(1)) //B1_FILIAL + B1_COD
    SB1->(DbGoTop())
    Count To nTotal
     
    //Abre o cadastro de complemento
    DbSelectArea('SB5')
    SB5->(DbSetOrder(1)) //B5_FILIAL + B5_COD
    SB5->(DbGoTop())
     
    //Posiciona no topo e percorre os registros
    SB1->(DbGoTop())
    While ! SB1->(Eof())
        nAtual++
        IncProc("Processando "+cValToChar(nAtual)+" de "+cValToChar(nTotal)+" ("+AllTrim(SB1->B1_COD)+")...")
         
        //Se não existir complemento
        If ! SB5->(DbSeek(FWxFilial('SB5') + SB1->B1_COD))
            //Foi feito através de RecLock, pois o MsExecAuto da MATA180 estava travando
            RecLock('SB5', .T.)
                B5_FILIAL    := FWxFilial('SB5')
                B5_COD       := SB1->B1_COD
                B5_CEME      := SB1->B1_DESC
                If lPosUM
                    B5_UMIND := '1'
                EndIf
            SB5->(MsUnlock())
             
            lMsErroAuto := .F.
             
            nOk++
            cOk += "- "+Alltrim(SB1->B1_COD)+";" + CRLF
        EndIf
         
        SB1->(DbSkip())
    EndDo
     
    //Se tiver erros ou inclusões, mostra mensagem
    If nOk != 0
        cMsg := "Foram analisados "+cValToChar(nTotal)+" produtos..." + CRLF + CRLF
        cMsg += "Sucesso na inclusão do complemento de "+cValToChar(nOk)+" produto(s):"+CRLF
        cMsg += cOk + CRLF
         
        Aviso("Atenção", cMsg, {"Ok"}, 2)
    EndIf
     
    //Atualiza o grupo de perguntas
    If MsgYesNo("Deseja atualizar o parâmetro do cadastro de produtos (F12)?", "Atenção")
        u_zAtuPerg("MTA010", "MV_PAR02", 1)
    EndIf
     
    MsgInfo("Processo concluído.", "Atenção")
     
    RestArea(aArea)
Return

Avisos:

Pessoal, o exemplo acima foi montado para um cenário onde tanto a SB1 como a SB5 estiverem como Compartilhadas (X2_MODO igual a C). Assim, ele vai sempre gerar 1 registro para cada SB5 que não tenha SB1.

Se o seu cenário for diferente, por exemplo, a SB5 for Exclusiva e a SB1 for Exclusiva, ai no if da linha 49, basta mudar para ! SB5->(DbSeek(SB1->B1_FILIAL + SB1->B1_COD)) . Que dessa forma, ele vai tentar buscar o registro para aquela filial e código atual da SB1. E na linha 52, ao invés de FWxFilial(“SB5”), você deve alterar para SB1->B1_FILIAL.

Agora se o seu cenário, for onde um tipo de compartilhamento for diferente do outro, por exemplo, SB5 for Exclusiva e a SB1 for Compartilhada, você terá que adaptar para que as filiais sejam percorridas, por exemplo, em um laço de repetição com For ou While, e ai dentro desse laço, acionar o DbSeek e RecLock na SB5.

Bom pessoal, por hoje é só.
Abraços e até a próxima.

Dan (Daniel Atilio)
Cristão de ramificação protestante. Especialista em Engenharia de Software pela FIB, graduado em Banco de Dados pela FATEC Bauru e técnico em informática pelo CTI da Unesp. Entusiasta de soluções Open Source e blogueiro nas horas vagas. Autor e mantenedor do portal Terminal de Informação.

8 Responses

  1. Felipe Pazetto disse:

    Olá Dan,

    Obrigado por compartilhar o material, só que tem um problema aí. Permita-me corrigi-lo.
    A linha 49 está levando em consideração apenas o código SB5 = SB1, porém sem considerar a filial.

    Caso contrário, ele vai adicionar SB5 de todas as filiais contidas na sua SB1 e não apenas da filial da SB1 que não tem SB5.

    Obrigado e até mais.

    • Fala Felipe, tudo joia?

      Primeiramente, obrigado pelo comentário e feedback.

      O cenário em que montei o artigo foi onde o X2_MODO esta igual para a SB5 e SB1 (acho que esqueci de mencionar no corpo do artigo), ambos como “C” de Compartilhados.

      Por isso, não vai acontecer de “adicionar SB5 de todas as filiais”, ele só vai adicionar 1 único registro pois esta usando FWxFilial.

      Quanto a pedir permissão, acha jovem, não precisa pedir não, pode ficar em paz. Se possível então, mande o trecho de código com a correção para o cenário que você pegou, que daí eu compartilho aqui no artigo para ajudar outras pessoas, onde o X2_MODO for diferente de Compartilhado entre SB1 e SB5 (ambas forem exclusivas ou uma ou outra for exclusiva).

      Enquanto aguardo o fonte que você vai enviar para eu complementar no artigo, vou deixar um aviso no fim dele, em que ele foi preparado numa base com ambas as tabelas compartilhadas, já citando as possíveis soluções com os outros tipos de compartilhamento.

      Fico no aguardo.

      Grande abraço.

  2. Felipe Pazetto disse:

    Não consegui responder direto na sua mensagem por um problema no meu navegador aqui, mas a partir da linha 42 troquei para:

    //Posiciona no topo e percorre os registros
    SB1->(DbGoTop())
    While ! SB1->(Eof()) .AND. Alltrim(SB1->B1_FILIAL+SB1->B1_COD) == Alltrim(SB5->B5_FILIAL+SB5->B5_COD)

    Não está ideal, mas está funcionando hahahhaha.

    Abraços

    • Opa, obrigado pelo feedback Felipe.

      Eu tinha achado que era na linha do Seek e dentro do RecLock que você estava falando (no comentário do dia 30/03). Em todo o caso eu já havia atualizado o artigo (com um aviso no fim) para quem tem ambas tabelas exclusivas (que é o seu cenário). Depois se quiser dar uma olhada mais acima, se quiser complementar com algo, fico no aguardo.

      Quanto ao trecho, ele deve ficar similar ao abaixo (para criar a SB5 conforme a SB1 posicionada), coloquei apenas o trecho das linhas 42 a 58:

          //Posiciona no topo e percorre os registros
          SB1->(DbGoTop())
          While ! SB1->(Eof())
              nAtual++
              IncProc("Processando "+cValToChar(nAtual)+" de "+cValToChar(nTotal)+" ("+AllTrim(SB1->B1_COD)+")...")
                
              //Se não existir complemento
              If ! SB5->(DbSeek(SB1->B1_FILIAL + SB1->B1_COD))
                  //Foi feito através de RecLock, pois o MsExecAuto da MATA180 estava travando
                  RecLock('SB5', .T.)
                      B5_FILIAL    := SB1->B1_FILIAL
                      B5_COD       := SB1->B1_COD
                      B5_CEME      := SB1->B1_DESC
                      If lPosUM
                          B5_UMIND := '1'
                      EndIf
                  SB5->(MsUnlock())
      

      Grande abraço.

  3. Fernando Vernier disse:

    No meu caso, a SB5 está exclusiva e a SB1 compartilhada, alguém ajustou o fonte dessa forma?

    Valeu.

    • Bom dia Fernando, tudo joia?
      Você pode adaptar a lógica para correr as filiais onde você vai atualizar a SB5, abaixo a lógica de exemplo:
      1. Criar uma variável com as filiais que vão ser percorridas
      Local aFiliais := {“0101”, “0201”, “0301”}

      2. Antes do While da SB1, percorre as filias e troca de filial conforme exemplo aqui – https://terminaldeinformacao.com/2021/12/01/como-mudar-de-empresa-e-filial-com-a-funcao-openfile/


      For nFilAtu := 1 To Len(aFiliais)
      cFilAnt := aFiliais[nFilAtu]
      cNumEmp := cEmpAnt+cFilAnt
      OpenFile(cNumEmp)

      SB1->(DbGoTop())
      While !…

      3. Ai o restante do código permanece, que ele vai correr os produtos e validar na filial posicionada se existe o complemento para aquele produto

      Um grande abraço.

Deixe uma resposta para Dan (Daniel Atilio)Cancelar resposta

Terminal de Informação