Árvore de páginas

Versões comparadas

Chave

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

Este documento apresenta um guia para criação de monitores exclusivos na funcionalidade de Gestão à Vista. Os monitores exclusivos são aqueles desenvolvidos pelos próprios clientes, para contemplar consultas além daquelas disponibilizadas pelos monitores padrões.

Para exemplo nesse guia, realizaremos o cadastro de um monitor com funcionalidades e filtros semelhantes ao monitor padrão de Situação de Ordens de Produção.

Deck of Cards
effectDuration0.5
idpassos
effectTypeslide
Card
defaulttrue
effectDuration0.5
idpasso-1
labelPasso 1 - Informações básicas
title1 - Informações básicas
effectTypeslide

O primeiro passo para criar o seu Monitor Exclusivo é acessar, no menu do ERP Protheus, o programa Gestão à Vista - Monitores Exclusivos (PCPMCUSTOM).

Caso já existam monitores cadastrados, eles serão exibidos em uma lista na tela inicial, permitindo que suas informações e filtros sejam editados e/ou excluídos.

Para realizar o cadastro de novos Monitores Exclusivos, basta acionar o botão "Adicionar", responsável pela abertura da tela que solicita as informações básicas do Monitor Exclusivo, e são elas: o título, o agrupador onde ele será exibido no momento de incluí-lo numa visão, uma breve descrição de seu objetivo, a forma como ele poderá apresentar as informações (opções de visualização/gráficos), além do campo "Api de Negócio" com o nome da classe ADVPL que conterá os métodos padrões para a busca de dados, detalhes e validação de filtros. Finalmente, enquanto o monitor estiver em fase de cadastro e validação, é importante manter o campo "Rascunho" ligado para que esse monitor apareça apenas para quem está o criando.

Acione o botão "Salvar" para efetivar a criação do cadastro do Monitor Exclusivo.

Multimedia
namenovo_monitor.mp4
width80%
height80%

Card
effectDuration0.5
idpasso-2
labelPasso 2 - Filtros
title2 - Filtros
effectTypeslide

Após o cadastro das informações básicas e a criação do Monitor Exclusivo, é necessário que sejam cadastrados seus filtros, que terão seus valores solicitados quando este monitor for incluído em uma visão, de forma semelhante ao que já funciona para os monitores padrões.

Seguindo o exemplo do monitor padrão de Situação de Ordens de Produção, serão cadastrados os seguintes filtros:

Totvs custom tabs box
tabsFilial,Produto,Status,Data de Referência,Período,Período personalizado (dias)
idsfilial,produto,status,data,periodo,personalizado
Totvs custom tabs box items
defaultyes
referenciafilial

Multimedia
namefiltro_filial.mp4
width80%
height80%

Totvs custom tabs box items
defaultno
referenciaproduto

Multimedia
namefiltro_produto.mp4
width80%
height80%

Totvs custom tabs box items
defaultno
referenciastatus

Multimedia
namefiltro_status.mp4
width80%
height80%

Totvs custom tabs box items
defaultno
referenciadata

Multimedia
namefiltro_filtrodata.mp4
width80%
height80%

Totvs custom tabs box items
defaultno
referenciaperiodo

Multimedia
namefiltro_tipoperiodo.mp4
width80%
height80%

Totvs custom tabs box items
defaultno
referenciapersonalizado

Multimedia
namefiltro_periodo.mp4
width80%
height80%

Card
effectDuration0.5
idpasso-3
labelPasso 3 - Criação/Compilação da Classe no RPO
title3 - Criação/Compilação da Classe no RPO
effectTypeslide

Após realizar o cadastro do monitor e seus filtros, é necessário criar a classe e compilar seu código fonte no RPO, permitindo que ela possa ser executada pelo monitor. Maiores detalhes sobre os requisitos desta classe e suas particularidades podem ser obtidos em Gestão à Vista - Monitores Exclusivos - Documentação Técnica

Para o exemplo utilizado neste guia, a classe StatusOPExclusivo tem seu código fonte conforme exemplo abaixo:

Bloco de código
languagecpp
firstline1
titleCódigo Fonte
linenumberstrue
collapsetrue
#INCLUDE "PROTHEUS.CH"
#INCLUDE "TOPCONN.CH"

/*/{Protheus.doc} StatusOPExclusivo
Classe para prover os dados do Monitor de Status de Ordem de Producao Exclusivo
@type Class
@author
@since
@version
@return Nil
/*/
Class StatusOPExclusivo FROM LongNameClass
    Static Method BuscaDados(oFiltros, cTipo, cSubTipo)
    Static Method BuscaDetalhes(oFiltros, nPagina)
    Static Method ValidaPropriedades(oFiltros)
EndClass

/*/{Protheus.doc} BuscaDados
Responsável por realizar a busca dos dados que serão exibidos no monitor
@type Class
@author
@since
@version
@param	oFiltros  , objeto Json, Contém as propriedades do monitor usadas para filtrar a query de busca
@param	cTipo     , caracter   , Tipo chart/info
@param	cSubTipo  , caracter   , Tipo de grafico pie/bar/column
@return cJsonDados, caracter   , Retorna um novo Json em formato texto, pronto para conversão e exibição no front
/*/
Method BuscaDados(oFiltros, cTipo, cSubTipo) Class StatusOPExclusivo
    Local aNames     := {}
    Local cAliasQry  := GetNextAlias()
    Local cJsonDados := ""
    Local cOp        := ""
    Local cQuery     := ""
    Local cStatusFlt := ArrTokStr(oFiltros["STATUS"])
    Local cStatusOp  := ""
    Local dDataIni   := dDataBase
    Local dDataFin   := dDataBase
    Local nIndice    := 0
    Local nIndSerie  := 0
    Local nPos       := 0
    Local nPosTag    := 0
    Local nTotOP     := 0
    Local oJsonRet   := JsonObject():New()
    Local oDados     := JsonObject():New()

    oJsonRet["alturaMinimaWidget"] := "350px"
    oJsonRet["alturaMaximaWidget"] := "500px"
    oJsonRet["categorias"]         := {"Situação"}
    oJsonRet["series"]             := {}
    oJsonRet["tags"]               := {}

    cQuery := montaQuery(oFiltros, @dDataIni, @dDataFin)
    dbUseArea(.T.,"TOPCONN",TcGenQry(,,cQuery),cAliasQry,.F.,.F.)

    oDados["Prevista"]         := {0, "rgb(255,255,0)"}     
    oDados["Em Aberto"]        := {0, "rgb(126,226,148)"}
    oDados["Iniciada"]         := {0, "rgb(255,128,0)"}    
    oDados["Ociosa"]           := {0, "rgb(128,128,128)"}   
    oDados["Enc. Parcialmente"] := {0, "rgb(0,0,165)"}
    oDados["Enc. Totalmente"]   := {0, "rgb(241,143,136)"}

    nPos := 0
    While (cAliasQry)->(!Eof())
        cOp := (cAliasQry)->C2_NUM+(cAliasQry)->C2_ITEM+(cAliasQry)->C2_SEQUEN+(cAliasQry)->C2_ITEMGRD
        cStatusOp := fStatusOp(cOp, (cAliasQry)->C2_TPOP, (cAliasQry)->C2_DATRF, (cAliasQry)->C2_QUJE, (cAliasQry)->C2_QUANT, (cAliasQry)->C2_DIASOCI, (cAliasQry)->C2_DATPRI) 
        If cStatusOp $ cStatusFlt
            Do Case
                Case  cStatusOp == "1"
                    ++oDados["Prevista"][1]
                Case  cStatusOp == "2"
                    ++oDados["Em Aberto"][1]
                Case  cStatusOp == "3"
                    ++oDados["Iniciada"][1]
                Case  cStatusOp == "4"
                    ++oDados["Ociosa"][1]
                Case  cStatusOp == "5"
                    ++oDados["Enc. Parcialmente"][1]
                Case  cStatusOp == "6"
                    ++oDados["Enc. Totalmente"][1]
            EndCase
        EndIf
        (cAliasQry)->(dbSkip())
    End
    (cAliasQry)->(dbCloseArea())

    aNames := oDados:GetNames()
    For nIndice := 1 To Len(aNames)
        If cSubTipo <> "pie"
            oDados[aNames[nIndice]][1] := {oDados[aNames[nIndice]][1]}
        EndIf
        PCPMonitorUtils():AdicionaSerieGraficoMonitor(oJsonRet["series"],@nIndSerie,oDados[aNames[nIndice]][2],oDados[aNames[nIndice]][1],aNames[nIndice])
        nTotOP += oDados[aNames[nIndice]][1]
    Next nIndice

    PCPMonitorUtils():AdicionaTagMonitor(oJsonRet["tags"],@nPosTag,"po-icon-calendar",dToC(dDataIni) + " - " + dToC(dDataFin))
    PCPMonitorUtils():AdicionaTagMonitor(oJsonRet["tags"],@nPosTag,"po-icon-star-filled",cValToChar(nTotOP) + IIF(nTotOP > 1," Ordens"," Ordem"))

    If oFiltros:HasProperty("STATUS") .And. ValType(oFiltros["STATUS"]) == "A" .And. Len(oFiltros["STATUS"]) < 6
        For nIndice := 1 To Len(oFiltros["STATUS"])
            PCPMonitorUtils():AdicionaTagMonitor(oJsonRet["tags"],@nPosTag,"po-icon-filter",buscaSerie(oFiltros["STATUS"][nIndice]))
        Next nIndice
    EndIf

    If oFiltros:HasProperty("PRODUTO") .And. ValType(oFiltros["PRODUTO"]) == "A"
        For nIndice := 1 To Len(oFiltros["PRODUTO"])
            PCPMonitorUtils():AdicionaTagMonitor(oJsonRet["tags"],@nPosTag,"po-icon-bar-code",oFiltros["PRODUTO"][nIndice])
        Next nIndice
    EndIf
    cJsonDados := oJsonRet:toJson()
    FwFreeArray(aNames)
    FreeObj(oDados)
    FreeObj(oJsonRet)
Return cJsonDados

/*/{Protheus.doc} BuscaDetalhes
Responsável por realizar a busca dos dados que serão exibidos no detalhamento do monitor
@type Class
@author
@since
@version
@param	oFiltros  , objeto Json , Contém as propriedades do monitor usadas para filtrar a query de busca
@param	nPagina   , numerico    , Número da página desejada para busca
@return cJsonDados, caracter    , Retorna um novo Json em formato texto, pronto para conversão e exibição no front
/*/
Method BuscaDetalhes(oFiltros, nPagina) Class StatusOPExclusivo
    Local cAliasQry  := GetNextAlias()
    Local cJsonDados := ""
    Local cQuery     := ""
    Local cOp        := ""
    Local cStatusFlt := ArrTokStr(oFiltros["STATUS"])
    Local cStatusOp  := ""
    Local dDataIni   := dDataBase
    Local dDataFin   := dDataBase
    Local lExpResult := .F.
    Local nIndice    := 0
    Local nPos       := 0
    Local nPosTag   := 0
    Local nStart     := 0
    Local oDados     := JsonObject():New()

    Default nPagina    := 1
    Default nTamPagina := 20

    If nPagina == 0
        lExpResult := .T.
    EndIf
    
    cQuery := montaQuery(oFiltros, @dDataIni, @dDataFin)
    dbUseArea(.T.,"TOPCONN",TcGenQry(,,cQuery),cAliasQry,.F.,.F.)

    oDados["items"]   := {}
    oDados["columns"] := montaColun(lExpResult)
    oDados["headers"] := {}
    oDados["tags"] := {}
    oDados["canExportCSV"] := .T.

    PCPMonitorUtils():AdicionaTagMonitor(oDados["tags"],@nPosTag,"po-icon-calendar",dToC(dDataIni) + " - " + dToC(dDataFin))

    If !Empty(oFiltros["SERIE"])
        PCPMonitorUtils():AdicionaTagMonitor(oDados["tags"],@nPosTag,"po-icon-filter",oFiltros["SERIE"])
    Else
        If oFiltros:HasProperty("STATUS") .And. ValType(oFiltros["STATUS"]) == "A" .And. Len(oFiltros["STATUS"]) < 6
            For nIndice := 1 To Len(oFiltros["STATUS"])
                PCPMonitorUtils():AdicionaTagMonitor(oDados["tags"],@nPosTag,"po-icon-filter",buscaSerie(oFiltros["STATUS"][nIndice]))
            Next nIndice
        EndIf
    EndIf

    If oFiltros:HasProperty("PRODUTO") .And. ValType(oFiltros["PRODUTO"]) == "A"
        For nIndice := 1 To Len(oFiltros["PRODUTO"])
            PCPMonitorUtils():AdicionaTagMonitor(oDados["tags"],@nPosTag,"po-icon-bar-code",oFiltros["PRODUTO"][nIndice])
        Next nIndice
    EndIf

    If nPagina > 1
		nStart := ( (nPagina-1) * nTamPagina )
		If nStart > 0
			(cAliasQry)->(DbSkip(nStart))
		EndIf
	EndIf

	nPos := 0
    While (cAliasQry)->(!Eof())
        cOp       := (cAliasQry)->C2_NUM+(cAliasQry)->C2_ITEM+(cAliasQry)->C2_SEQUEN+(cAliasQry)->C2_ITEMGRD
        cStatusOp := fStatusOp(cOp, (cAliasQry)->C2_TPOP, (cAliasQry)->C2_DATRF, (cAliasQry)->C2_QUJE, (cAliasQry)->C2_QUANT, (cAliasQry)->C2_DIASOCI, (cAliasQry)->C2_DATPRI, oFiltros["FILIAL"])
        
        If !Empty(oFiltros["SERIE"])
            If oFiltros["SERIE"] == buscaSerie(cStatusOp)
                aAdd(oDados["items"], JsonObject():New())
                nPos++
                oDados["items"][nPos]["C2_FILIAL"]  := (cAliasQry)->C2_FILIAL
                oDados["items"][nPos]["C2_OP"]      := Iif( !Empty((cAliasQry)->C2_OP), (cAliasQry)->C2_OP, cOp)
                oDados["items"][nPos]["C2_PRODUTO"] := (cAliasQry)->C2_PRODUTO
                oDados["items"][nPos]["B1_DESC"]    := (cAliasQry)->B1_DESC
                oDados["items"][nPos]["C2_LOCAL"]   := (cAliasQry)->C2_LOCAL
                oDados["items"][nPos]["C2_DATPRI"]  := PCPMonitorUtils():FormataData((cAliasQry)->C2_DATPRI, 5)
                oDados["items"][nPos]["C2_DATPRF"]  := PCPMonitorUtils():FormataData((cAliasQry)->C2_DATPRF, 5)
                oDados["items"][nPos]["C2_QUJE"]    := (cAliasQry)->C2_QUJE
                oDados["items"][nPos]["C2_QUANT"]   := (cAliasQry)->C2_QUANT
                oDados["items"][nPos]["C2_DIASOCI"] := (cAliasQry)->C2_DIASOCI
                oDados["items"][nPos]["STATUS"]     := cStatusOp
            EndIf
        Else
            If cStatusOp $ cStatusFlt
                aAdd(oDados["items"], JsonObject():New())
                nPos++
                oDados["items"][nPos]["C2_FILIAL"]  := (cAliasQry)->C2_FILIAL
                oDados["items"][nPos]["C2_OP"]      := Iif( !Empty((cAliasQry)->C2_OP), (cAliasQry)->C2_OP, cOp)
                oDados["items"][nPos]["C2_PRODUTO"] := (cAliasQry)->C2_PRODUTO
                oDados["items"][nPos]["B1_DESC"]    := (cAliasQry)->B1_DESC
                oDados["items"][nPos]["C2_LOCAL"]   := (cAliasQry)->C2_LOCAL
                oDados["items"][nPos]["C2_DATPRI"]  := PCPMonitorUtils():FormataData((cAliasQry)->C2_DATPRI, 5)
                oDados["items"][nPos]["C2_DATPRF"]  := PCPMonitorUtils():FormataData((cAliasQry)->C2_DATPRF, 5)
                oDados["items"][nPos]["C2_QUJE"]    := (cAliasQry)->C2_QUJE
                oDados["items"][nPos]["C2_QUANT"]   := (cAliasQry)->C2_QUANT
                oDados["items"][nPos]["C2_DIASOCI"] := (cAliasQry)->C2_DIASOCI
                oDados["items"][nPos]["STATUS"]     := cStatusOp
            EndIf
        EndIf
        (cAliasQry)->(dbSkip())

        If !lExpResult .And. nPos >= nTamPagina
            Exit
        EndIf
    End
    oDados["hasNext"] := (cAliasQry)->(!Eof())
    (cAliasQry)->(dbCloseArea())
    cJsonDados := oDados:toJson()
    FreeObj(oDados)
Return cJsonDados

/*/{Protheus.doc} montaColun
Realiza a criação de objeto Json que define as colunas utilizadas na grid de detalhamento do monitor
@type Static Function
@author
@since
@version
@param  lExpResult, logico, Indica se trata todas as colunas como visible
@return aColumns, array objetos, Contém as definições das colunas da grid do monitor
/*/
Static Function montaColun(lExpResult)
    Local aColunas   := {}
    Local aLabels    := {}
    Local nIndice    := 0
    Local nIndLabels := 0

    PCPMonitorUtils():AdicionaLabelsColunaTabela(aLabels,@nIndLabels,"1","rgb(255,255,0)","Prevista","rgb(0,0,0)")
    PCPMonitorUtils():AdicionaLabelsColunaTabela(aLabels,@nIndLabels,"2","rgb(126,226,148)","Em aberto","rgb(255,255,255)")
    PCPMonitorUtils():AdicionaLabelsColunaTabela(aLabels,@nIndLabels,"3","rgb(255,128,0)","Iniciada","rgb(255,255,255)")
    PCPMonitorUtils():AdicionaLabelsColunaTabela(aLabels,@nIndLabels,"4","rgb(128,128,128)","Ociosa","rgb(255,255,255)")
    PCPMonitorUtils():AdicionaLabelsColunaTabela(aLabels,@nIndLabels,"5","rgb(0,0,165)","Enc. Parcialmente","rgb(255,255,255)")
    PCPMonitorUtils():AdicionaLabelsColunaTabela(aLabels,@nIndLabels,"6","rgb(241,143,136)","Enc. Totalmente","rgb(255,255,255)")
    PCPMonitorUtils():AdicionaColunaTabela(aColunas,@nIndice,"STATUS","Status","cellTemplate",.T.,.T.,aLabels) 
    PCPMonitorUtils():AdicionaColunaTabela(aColunas,@nIndice,"C2_FILIAL","Filial","string",lExpResult)
    PCPMonitorUtils():AdicionaColunaTabela(aColunas,@nIndice,"C2_OP","OP","string",.T.)
    PCPMonitorUtils():AdicionaColunaTabela(aColunas,@nIndice,"C2_PRODUTO","Produto","string",.T.)
    PCPMonitorUtils():AdicionaColunaTabela(aColunas,@nIndice,"B1_DESC","Desc. Produto","string",lExpResult)
    PCPMonitorUtils():AdicionaColunaTabela(aColunas,@nIndice,"C2_LOCAL","Armazém","string",.T.)
    PCPMonitorUtils():AdicionaColunaTabela(aColunas,@nIndice,"C2_DATPRI","Previsão Início","string",.T.)
    PCPMonitorUtils():AdicionaColunaTabela(aColunas,@nIndice,"C2_DATPRF","Previsão Entrega","string",.T.)
    PCPMonitorUtils():AdicionaColunaTabela(aColunas,@nIndice,"C2_QUANT","Quantidade","string",.T.)
    PCPMonitorUtils():AdicionaColunaTabela(aColunas,@nIndice,"C2_QUJE","Qtd. Prod","string",.T.)
Return aColunas

/*/{Protheus.doc} montaQuery
Realiza a criação de objeto Json que define as colunas utilizadas na grid de detalhamento do monitor
@type Static Function
@author
@since
@version
@param	oFiltros, objeto Json, Contém as propriedades do monitor usadas para filtrar a query de busca
@param	dDataIni, data       , Data inicial do filtro
@param	dDataFin, data       , Data final do filtro
@return cQuery  , caracter   , Query utilizada para busca no banco de dados
/*/
Static Function montaQuery(oFiltros, dDataIni, dDataFin)
    Local cPerDias  := cValtoChar(oFiltros["PERIODO"])
    Local cProdutos := ""
    Local cQuery    := ""
    Local nIndice   := 0

    cQuery := " SELECT "
    cQuery += "     SC2.C2_FILIAL, SC2.C2_NUM, SC2.C2_ITEM, SC2.C2_SEQUEN, SC2.C2_ITEMGRD, SC2.C2_OP, SC2.C2_LOCAL,"
	cQuery += "     SC2.C2_PRODUTO, SB1.B1_DESC, SC2.C2_TPOP, SC2.C2_DATRF, SC2.C2_DATPRF, SC2.C2_QUJE, SC2.C2_QUANT, SC2.C2_DIASOCI, SC2.C2_DATPRI"
    cQuery += " FROM " +RetSqlName("SC2")+ " SC2 "
    cQuery += " LEFT JOIN "+RetSqlName("SB1")+" SB1 ON SB1.B1_FILIAL = '"+xFilial("SB1",oFiltros["FILIAL"])+"' AND SB1.B1_COD = SC2.C2_PRODUTO AND SB1.D_E_L_E_T_ = ' ' " 
    cQuery += " WHERE SC2.C2_FILIAL = '"+ xFilial("SC2", oFiltros["FILIAL"])+"' "

    If oFiltros:HasProperty("PRODUTO") .And. ValType(oFiltros["PRODUTO"]) == "A"
        For nIndice := 1 To Len(oFiltros["PRODUTO"])
            If Empty(cProdutos)
                cProdutos := "'" + oFiltros["PRODUTO"][nIndice] + "'"
            Else
                cProdutos +=  ",'" + oFiltros["PRODUTO"][nIndice] + "'"
            EndIf
        Next nIndice
    EndIf
    If !Empty(cProdutos)
        cQuery += " AND SC2.C2_PRODUTO IN ("+cProdutos+") "
    EndIf
    If oFiltros["TIPOPERIODO"] == "X"
        If Val(cPerDias) >= 0
            dDataFin := PCPMonitorUtils():RetornaPeriodoFinal(oFiltros["TIPOPERIODO"],dDataIni,cPerDias)
        Else
            dDataIni := PCPMonitorUtils():RetornaPeriodoInicial(oFiltros["TIPOPERIODO"],dDataFin,cValtoChar(ABS(Val(cPerDias))))
        EndIf
    Else
        dDataIni := PCPMonitorUtils():RetornaPeriodoInicial(oFiltros["TIPOPERIODO"],dDataFin,cPerDias)
        dDataFin := PCPMonitorUtils():RetornaPeriodoFinal(oFiltros["TIPOPERIODO"],dDataIni,cPerDias)
    EndIf
    cQuery += " AND SC2."+oFiltros["FILTRODATA"]+" BETWEEN '"+dToS(dDataIni)+"' AND '"+dToS(dDataFin)+"' "
    cQuery += " AND SC2.D_E_L_E_T_ = ' ' "
Return cQuery

/*/{Protheus.doc} Static Function fStatusOp
Retorna o Status da Ordem de Produção
@type  Static Function
@author
@since
@version
@param  cOP       , caracter, Ordem de Produção
@param  cTpo      , caracter, Tipo da Ordem de Produção / Firme ou Prevista
@param  cDatrf    , caracter, Data de Encerramento
@param  nQuje     , numerico, Quantidade Apontada
@param  nQuant    , numerico, Quantidade Prevista
@param  cFilterFil, caracter, Filial informada no filtro
@return cStatusOp , caracter, Status da OP - 1-Prevista/2-Em aberto/3-Iniciada/4-Ociosa/5-Enc.Parcialmente/6-Enc.Totalmente
/*/
Static Function fStatusOp(cOp, cTpo, cDatrf, nQuje, nQuant, cDatOci, cDTINI, cFilterFil)
    Local cAliasTemp  := ""
    Local cQuery 	  := ""
    Local dEmissao	  := dDatabase
    Local nRegSD3	  := 0
    Local nRegSH6	  := 0

    Default cOp       := ""
    Default cTpo      := ""
    Default cDatrf    := ""
    Default nQuant    := 0
    Default nQuje     := 0
    
    cDTINI := STOD(cDTINI)

    If cTpo == "P" //1-Prevista
        Return "1"
    EndIf
    If cTpo == "F" .And. !Empty(cDatrf) .And. (nQuje < nQuant)  //5-Enc.Parcialmente
        Return "5"
    EndIf
    If cTpo == "F" .And. !Empty(cDatrf) .And. (nQuje >= nQuant) //6-Enc.Totalmente
        Return "6"
    EndIf

    cAliasTemp:= "SD3TMP"
    cQuery	  := "  SELECT COUNT(*) AS RegSD3, MAX(D3_EMISSAO) AS EMISSAO "
    cQuery	  += "   FROM " + RetSqlName("SD3")
    cQuery	  += "   WHERE D3_FILIAL   = '" + xFilial( "SC2", cFilterFil ) + "'"
    cQuery	  += "     AND D3_OP 	   = '" + cOp + "'"
    cQuery	  += "     AND D3_ESTORNO <> 'S' "
    cQuery	  += "     AND D_E_L_E_T_  = ' '"
    cQuery    += " 	   GROUP BY D3_EMISSAO "
    cQuery    := ChangeQuery(cQuery)
    dbUseArea (.T., "TOPCONN", TCGENQRY(,,cQuery), cAliasTemp, .F., .T.)

    If !SD3TMP->(Eof())
        dEmissao := STOD(SD3TMP->EMISSAO)
        nRegSD3 := SD3TMP->RegSD3
    EndIf

    cAliasTemp:= "SH6TMP"
    cQuery	  := "  SELECT COUNT(*) AS REGSH6 "
    cQuery	  += "   FROM " + RetSqlName("SH6")
    cQuery	  += "   WHERE H6_FILIAL   = '" + xFilial("SH6", cFilterFil) + "'"
    cQuery	  += "     AND H6_OP 	   = '" + cOp + "'"
    cQuery	  += "     AND D_E_L_E_T_  = ' '"
    cQuery    := ChangeQuery(cQuery)
    dbUseArea ( .T., "TOPCONN", TCGENQRY(,,cQuery), cAliasTemp, .F., .T.)

    If !SH6TMP->(Eof())
        nRegSH6 := SH6TMP->REGSH6
    EndIf

    SD3TMP->(DbCloseArea())
    SH6TMP->(DbCloseArea())

    If cTpo == "F" .And. Empty(cDatrf)
        If (nRegSD3 < 1 .And. nRegSH6 < 1) .And. (Max(dDataBase - cDTINI,0) < If(cDatOci==0,1,cDatOci)) //2-Em aberto            
            Return "2"
        EndIf
        If (nRegSD3 > 0 .Or. nRegSH6 > 0) .And. (Max((ddatabase - dEmissao),0) > If(cDatOci >= 0,-1,cDatOci)) //3-Iniciada
            Return "3"
        EndIf
        If (Max((ddatabase - dEmissao),0) > cDatOci .Or. Max((ddatabase - cDTINI),0) >= cDatOci)  //4-Ociosa
           Return "4"
        EndIf
    EndIf
Return

/*/{Protheus.doc} ValidaPropriedades
Valida os dados informados nas propriedades do Monitor
@type Method
@author
@since
@version
@param  oFiltros, objeto json, Objeto json com os filtros para a consulta dos dados
@return aRetorno, array      , [1] logico - indica se os dados são válidos [2] caracter - mensagem de erro
/*/
Method ValidaPropriedades(oFiltros) Class StatusOPExclusivo
    Local aRetorno := {.T.,""}

    PCPMonitorUtils():ValidaPropriedadeFilial(oFiltros["FILIAL"],aRetorno)

    If aRetorno[1] .And. oFiltros["TIPOPERIODO"] == "X"
        If !oFiltros:HasProperty("PERIODO") .Or. oFiltros["PERIODO"] == Nil .Or. Empty(oFiltros["PERIODO"])
            aRetorno[1] := .F.
            aRetorno[2] := "Deve ser informada a quantidade de dias para o período personalizado."
        EndIf
    EndIf
Return aRetorno

/*/{Protheus.doc} buscaSerie
Realiza um "De Para" buscando o texto relativo ao código de status das OPs
@type Static Function
@author
@since
@version
@param  cStatusOp , caracter, Código do status da ordem de produção
@return cDscStatus, caracter, Descrição do status da ordem de produção
/*/
Static Function buscaSerie(cStatusOp)
    Local cDscStatus := ""

    Do Case
        Case cStatusOp == "1"
            cDscStatus :=  "Prevista"
        Case cStatusOp == "2"
            cDscStatus := "Em aberto"
        Case cStatusOp == "3"
            cDscStatus := "Iniciada"
        Case cStatusOp == "4"
            cDscStatus := "Ociosa"
        Case cStatusOp == "5"
            cDscStatus := "Enc. Parcialmente"
        Case cStatusOp == "6"
            cDscStatus := "Enc. Totalmente"
    EndCase
Return cDscStatus    
Card
effectDuration0.5
idpasso-4
labelPasso 4 - Adicionar monitor à visão
title4 - Adicionar monitor à visão
effectTypeslide

Após os cadastros terem sido realizados e o código fonte ter sido compilado, o próximo passo é adicionar o monitor exclusivo em uma visão e verificar as informações retornadas, a correta aplicação dos filtros, a apresentação do monitor e os respectivos registros de detalhe exibidos.

Multimedia
nameincluir_monitor_exclusivo.mp4
width80%
height80%

Card
effectDuration0.5
idpasso-5
labelPasso 5 - Liberar Monitor Exclusivo
title5 - Liberar Monitor Exclusivo
effectTypeslide

Agora que verificamos que tudo está correto, o passo final é desmarcar a opção de "Rascunho" para que outros usuários possam adicionar o monitor em suas visões. Se for necessário restringir o uso desse monitor para algum usuário ou grupo de usuários, é possível fazê-lo através do cadastro de privilégios para o programa PCPMONITOR no SIGACFG.

Multimedia
nameliberando_monitor.mp4
width80%
height80%