01. VISÃO GERAL

O objetivo deste monitor é apresentar um gráfico com a quantidade perdida dos produtos classificadas de acordo com seu motivo de perda, dentro de um período anterior configurado, permitindo a seleção dos produtos, recursos e motivos que serão monitorados.
Estas perdas são informadas através da rotina Apontamento de perda - MATA685 ou do APP Minha Produção e os motivos possíveis são previamente cadastrados através da rotina Motivo Refugo - SFCA003.

02. TIPOS DISPONÍVEIS

03. FILTROS

Os filtros para definição do escopo a ser monitorado são os seguintes:

Filtro Descrição
Filial*Seleção simples da filial a ser monitorada, a partir da lista das filiais disponíveis.
Produto

Seleção múltipla dos produtos a serem monitorados, a partir da informação do código ou da pesquisa dentre os produtos disponíveis para a filial.

RecursoSeleção múltipla dos recursos a serem monitorados, a partir da informação do código ou da pesquisa dentre os recursos disponíveis para a filial.
Motivos de Perda

Seleção múltipla dos motivos de perda a serem monitoradas, a partir da lista de motivos cadastrados através da rotina Motivo Refugo - SFCA003.
Obs.: como facilitador, já que o número de motivos possíveis depende do cadastro efetuado na rotina Motivo Refugo - SFCA003, caso não seja selecionado nenhum motivo, automaticamente todos serão considerados para o monitoramento.

Período*

Indica o tipo de período que será monitorado: Dia Atual, Semana Atual, Quinzena Atual, Mês Atual ou Personalizado.

Importante: as semanas compreendem os dados entre domingo e o sábado subsequente, a primeira quinzena compreende os dados entre os dias 01 e 15, enquanto a segunda quinzena compreende os dados entre os dias 16 e o último dia do mês.

Período personalizado (dias)

Indica o número de dias anteriores que serão monitorados, ou seja, o número de dias será considerado até a data atual, quando selecionado o tipo de período Personalizado.

* Filtro obrigatório


Importante: Atenção ao selecionar os produtos que serão exibidos no monitor para que todos tenham a mesma unidade de medida padrão, evitando que seja impossível analisar os dados referentes às quantidades, já que não é realizada conversão entre diferentes unidades. A dica é incluir em suas visões pelo menos um monitor diferente para cada grupo de produtos com a mesma unidade de medida.

04. TAGS AUXILIARES

As Tags auxiliam na identificação dos filtros utilizados para delimitar o escopo de um monitor, sem necessidade de editá-los.

TagÍconeDescrição
Período de abrangência

Data de/até referente ao período exibido no monitor.
Total de Apontamentos de Perda

Quantidade total de apontamentos de perda efetuados dos produtos, recursos e motivos selecionados exibidos pelo monitor.
Total de Quantidade Perdida

Quantidade total da perda de produtos no período exibido pelo monitor.
Motivo de Perda

Motivos que estão sendo monitorados, somente quando forem selecionados nos filtros.
Produto

Códigos dos produtos que estão sendo monitorados, quando selecionados.
Recurso

Códigos dos recursos que estão sendo monitorados, quando selecionados.

05. DETALHES

Apontamentos de perda dos produtos, recursos e motivos selecionados, com data de perda no período de abrangência do monitor, com possibilidade de detalhar os apontamentos de cada motivo separadamente.

São exibidos dados referentes à Filial, Motivo da Perda, Ordem de Produção, Operação, Produto, Armazém Origem, Data da Perda, Quantidade Perdida, Unidade de Medida, Tipo, Operador e Recurso.

Os registros podem ser exportados para o formato .CSV através do botão Exportar Planilha.

06. TABELAS UTILIZADAS

07. EXEMPLOS




08. CÓDIGO FONTE

#INCLUDE "PROTHEUS.CH"
#INCLUDE "TOPCONN.CH"
#INCLUDE "PCPMONITOR.CH"
#INCLUDE "PCPMONITORDEF.CH"

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

/*/{Protheus.doc} CargaMonitor
Realiza a carga do monitor no banco de dados, permitindo a exibição de um exemplo desse monitor para 
ser escolhido para uso na aplicação.
@type Class
@author 
@since 
@version 
@return lRet, logico, Define se a carga do Monitor foi realizada com sucesso
/*/
Method CargaMonitor() Class StatusMotivoPerdas
    Local aCategoria := {}
    Local aTags      := {}
    Local lRet       := .T.
    Local nPosTag    := 0
    Local oCarga     := PCPMonitorCarga():New()
    Local oSeries    := JsonObject():New()
        
    If !PCPMonitorCarga():monitorAtualizado("StatusMotivoPerdas")
        oSeries["FH"] := {1, COR_AMARELO}  //"Falha Humana"
        oSeries["FM"] := {2, COR_VERMELHO} //"Falha Mecânica"  
        oSeries["FP"] := {4, COR_LARANJA}  //"Falha Matéria Prima"
        oSeries["RB"] := {9, COR_CINZA}    //"Rebarba"

        PCPMonitorUtils():AdicionaTagMonitor(aTags,@nPosTag,"po-icon-calendar","01/02/2023 - 28/02/2023")
        PCPMonitorUtils():AdicionaTagMonitor(aTags,@nPosTag,"po-icon-star",STR0156+": 16") //"Perda"
        PCPMonitorUtils():AdicionaTagMonitor(aTags,@nPosTag,"po-icon-star-filled","5 "+STR0197) //"Apontamentos"

        oCarga:setaTitulo(STR0275) //"Motivos de Perda"
        oCarga:setaObjetivo(STR0276) //"Acompanhar o motivo das perdas registradas no sistema através da rotina de apontamento de perdas num determinado período."
        oCarga:setaAgrupador("PCP")
        oCarga:setaFuncaoNegocio("StatusMotivoPerdas")
        oCarga:setaTipoPadrao("chart")
        oCarga:setaTiposPermitidos("chart")
        oCarga:setaTiposGraficoPermitidos("pie;bar;column")
        oCarga:setaTipoGraficoPadrao("pie")
        oCarga:setaTipoDetalhe("detalhe")
        oCarga:setaExemploJsonGrafico(oSeries,aTags,aCategoria,"pie")
       
        oCarga:setaPropriedadeFilial("01_BC_FILIAL")
        oCarga:setaPropriedadeProduto("02_BC_PRODUTO",.T.)
        oCarga:setaPropriedadeRecurso("03_BC_RECURSO",.T.)
        oCarga:setaPropriedadeLookupTabela("04_BC_MOTIVO",STR0275,.T.,"CYO","CYO_CDRF","CYO_DSRF") //"Motivos de Perda"
        oCarga:setaPropriedadePeriodoAtual("05_TIPOPERIODO","D","06_PERIODO")
        
        If !oCarga:gravaMonitorPropriedades()
            lRet := .F.
        EndIf
        oCarga:Destroy()
    EndIf
    FwFreeArray(aCategoria)
    FwFreeArray(aTags)
    FreeObj(oSeries)
Return lRet


/*/{Protheus.doc} BuscaDados
Responsável por realizar a busca dos dados que serão exibidos no monitor (gráfico ou texto)
@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 StatusMotivoPerdas
    Local aNames     := {}
    Local cAliasQry  := GetNextAlias()
    Local cJsonDados := ""
    Local cQuery     := ""
    Local dDataIni   := dDataBase
    Local dDataFin   := dDataBase
    Local nIndice    := 0
    Local nPosTag    := 0
    Local nTotApont  := 0
    Local nTotQuant  := 0
    Local oDados     := JsonObject():New()
    Local oJsonRet   := JsonObject():New()

    oJsonRet["alturaMinimaWidget"] := "350px"
    oJsonRet["alturaMaximaWidget"] := "500px"
    oJsonRet["categorias"]         := {STR0275} //"Motivos de Perda"
    oJsonRet["series"]             := {}
    oJsonRet["tags"]               := {}
    oJsonRet["detalhes"]           := {}

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

    nIndice := 0
    While (cAliasQry)->(!Eof())
        ++nIndice

        oDados[AllTrim((cAliasQry)->BC_MOTIVO)] := JsonObject():New()
        oDados[AllTrim((cAliasQry)->BC_MOTIVO)] := {(cAliasQry)->QT_PERDA, PCPMonitorUtils():RetornaCorSerie(nIndice)}

        nTotApont += (cAliasQry)->NR_APONT
        nTotQuant += (cAliasQry)->QT_PERDA

        (cAliasQry)->(dbSkip())
    End
    (cAliasQry)->(dbCloseArea())

    aNames := oDados:GetNames()
    For nIndice := 1 To Len(aNames)
        aAdd(oJsonRet["series"], JsonObject():New())	
        oJsonRet["series"][nIndice]["label"]   := IIF(AllTrim(aNames[nIndice])<>"",aNames[nIndice],"-")
        oJsonRet["series"][nIndice]["color"]   := oDados[aNames[nIndice]][2]
        oJsonRet["series"][nIndice]["tooltip"] := IIF(AllTrim(aNames[nIndice])<>"", aNames[nIndice] + " " + Capital(AllTrim(Posicione("CYO",1,xFilial("CYO",oFiltros["01_BC_FILIAL"])+aNames[nIndice], "CYO_DSRF"))), "- " + STR0286) + ": " + cValToChar(oDados[aNames[nIndice]][1])
        If cSubTipo <> 'pie'
            oJsonRet["series"][nIndice]["data"] := {}
            aAdd(oJsonRet["series"][nIndice]["data"], oDados[aNames[nIndice]][1])
        Else
            oJsonRet["series"][nIndice]["data"] := oDados[aNames[nIndice]][1]
        EndIf
    Next nIndice

    PCPMonitorUtils():AdicionaTagMonitor(oJsonRet["tags"],@nPosTag,"po-icon-calendar",dToC(dDataIni) + " - " + dToC(dDataFin))
    PCPMonitorUtils():AdicionaTagMonitor(oJsonRet["tags"],@nPosTag,"po-icon-star",STR0156 + ": " + cValToChar(nTotQuant)) //"Perda"
    PCPMonitorUtils():AdicionaTagMonitor(oJsonRet["tags"],@nPosTag,"po-icon-star-filled",cValToChar(nTotApont) + IIF(nTotApont > 1," "+STR0197," "+STR0280)) //"Apontamentos" //"Apontamento"

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

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

    If oFiltros:HasProperty("03_BC_RECURSO") .And. ValType(oFiltros["03_BC_RECURSO"]) == "A"
        For nIndice := 1 To Len(oFiltros["03_BC_RECURSO"])
            PCPMonitorUtils():AdicionaTagMonitor(oJsonRet["tags"],@nPosTag,"po-icon-manufacture",oFiltros["03_BC_RECURSO"][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 StatusMotivoPerdas
    Local cAliasQry  := GetNextAlias()
    Local cJsonDados := ""
    Local cQuery     := ""
    Local cRoteiro   := ""
    Local cSerie     := ""
    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

    If !Empty(oFiltros["SERIE"])
        cSerie := oFiltros["SERIE"]
    EndIf
    
    cQuery := montaQuery(oFiltros, @dDataIni, @dDataFin,2)
    dbUseArea(.T.,"TOPCONN",TcGenQry(,,cQuery),cAliasQry,.F.,.F.)

    oDados["items"]   := {}
    oDados["columns"] := bscColunas(lExpResult,cSerie)
    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",cSerie + " " + IIF(cSerie <> "-",Capital(AllTrim(Posicione("CYO",1,xFilial("CYO",oFiltros["01_BC_FILIAL"])+cSerie, "CYO_DSRF"))),STR0286))
    Else
        If oFiltros:HasProperty("04_BC_MOTIVO") .And. ValType(oFiltros["04_BC_MOTIVO"]) == "A"
            For nIndice := 1 To Len(oFiltros["04_BC_MOTIVO"])
                PCPMonitorUtils():AdicionaTagMonitor(oDados["tags"],@nPosTag,"po-icon-filter",oFiltros["04_BC_MOTIVO"][nIndice])
            Next nIndice
        EndIf
    EndIf

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

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

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

	nPos := 0
    While (cAliasQry)->(!Eof())
        aAdd(oDados["items"], JsonObject():New())
        nPos++
        cRoteiro := IIF(!Empty((cAliasQry)->C2_ROTEIRO),(cAliasQry)->C2_ROTEIRO,IIF(!Empty((cAliasQry)->B1_OPERPAD),(cAliasQry)->B1_OPERPAD,"01"))

        oDados["items"][nPos]["BC_FILIAL"]  := (cAliasQry)->BC_FILIAL
        oDados["items"][nPos]["BC_TIPO"]    := (cAliasQry)->BC_TIPO
        oDados["items"][nPos]["BC_MOTIVO"]  := (cAliasQry)->BC_MOTIVO
        oDados["items"][nPos]["CYO_DSRF"]   := AllTrim(Posicione("CYO",1,xFilial("CYO",oFiltros["01_BC_FILIAL"])+(cAliasQry)->BC_MOTIVO, "CYO_DSRF"))
        oDados["items"][nPos]["BC_OP"]      := (cAliasQry)->BC_OP
        oDados["items"][nPos]["BC_OPERAC"]  := (cAliasQry)->BC_OPERAC
        oDados["items"][nPos]["G2_DESCRI"]  := AllTrim(Posicione("SG2",1,xFilial("SG2",oFiltros["01_BC_FILIAL"])+(cAliasQry)->BC_PRODUTO+cRoteiro+(cAliasQry)->BC_OPERAC,"G2_DESCRI"))
        oDados["items"][nPos]["BC_PRODUTO"] := (cAliasQry)->BC_PRODUTO
        oDados["items"][nPos]["B1_DESC"]    := (cAliasQry)->B1_DESC
        oDados["items"][nPos]["BC_LOCORIG"] := (cAliasQry)->BC_LOCORIG
        oDados["items"][nPos]["BC_QUANT"]   := (cAliasQry)->BC_QUANT
        oDados["items"][nPos]["B1_UM"]      := (cAliasQry)->B1_UM
        oDados["items"][nPos]["BC_OPERADO"] := (cAliasQry)->BC_OPERADO
        oDados["items"][nPos]["BC_DATA"]    := PCPMonitorUtils():FormataData((cAliasQry)->BC_DATA, 5)
        oDados["items"][nPos]["BC_RECURSO"] := (cAliasQry)->BC_RECURSO
        oDados["items"][nPos]["H1_DESCRI"]  := PCPMonitorUtils():RetornaDescricaoRecurso(oFiltros["01_BC_FILIAL"],(cAliasQry)->BC_RECURSO)

        (cAliasQry)->(dbSkip())

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

/*/{Protheus.doc} bscColunas
Cria array de objetos no formato poTableColumn com as colunas da table de detalhamento
@type Static Function
@author 
@since 
@version 
@param  lExpResult, logico, Indica se trata todas as colunas como visible
@param  cSerie    , caracter, Motivo selecionado para filtrar detalhes (quando selecionado)
@return aColumns, array objetos, Contém as definições das colunas da grid do monitor
/*/
Static Function bscColunas(lExpResult, cSerie)
    Local aColunas   := {}
    Local aLabels    := {}
    Local nIndice    := 0
    Local nIndLabels := 0

    PCPMonitorUtils():AdicionaColunaTabela(aColunas,@nIndice,"BC_FILIAL",STR0058,"string",lExpResult) //"Filial"
    PCPMonitorUtils():AdicionaColunaTabela(aColunas,@nIndice,"BC_MOTIVO",STR0159,"string",IIF(lExpResult .Or. cSerie == "",.T.,.F.)) //"Motivo"
    PCPMonitorUtils():AdicionaColunaTabela(aColunas,@nIndice,"CYO_DSRF", STR0160,"string",IIF(lExpResult .Or. cSerie == "",.T.,.F.)) //"Desc. Motivo"
    PCPMonitorUtils():AdicionaColunaTabela(aColunas,@nIndice,"BC_OP",STR0076,"string",.T.) //"OP"
    PCPMonitorUtils():AdicionaColunaTabela(aColunas,@nIndice,"BC_OPERAC",STR0077,"string",.T.) //"Operação"
    PCPMonitorUtils():AdicionaColunaTabela(aColunas,@nIndice,"G2_DESCRI" ,STR0078,"string",lExpResult) //"Desc. Oper"
    PCPMonitorUtils():AdicionaColunaTabela(aColunas,@nIndice,"BC_PRODUTO",STR0074,"string",.T.) //"Produto"
    PCPMonitorUtils():AdicionaColunaTabela(aColunas,@nIndice,"B1_DESC",STR0075,"string",lExpResult) //"Desc. Produto"
    PCPMonitorUtils():AdicionaColunaTabela(aColunas,@nIndice,"BC_LOCORIG",STR0277,"string",.T.) //"Armazém Origem"
    PCPMonitorUtils():AdicionaColunaTabela(aColunas,@nIndice,"BC_DATA",STR0278,"string",.T.) //"Data Perda"
    PCPMonitorUtils():AdicionaColunaTabela(aColunas,@nIndice,"BC_QUANT",STR0091,"string",.T.) //"Quantidade"
    PCPMonitorUtils():AdicionaColunaTabela(aColunas,@nIndice,"B1_UM",STR0180,"string",.T.) //"Un. Medida"
    PCPMonitorUtils():AdicionaLabelsColunaTabela(aLabels,@nIndLabels,"R",COR_VERMELHO,STR0282,COR_BRANCO) //"Refugo"
    PCPMonitorUtils():AdicionaLabelsColunaTabela(aLabels,@nIndLabels,"S",COR_AMARELO,STR0283,COR_PRETO) //"Scrap"
    PCPMonitorUtils():AdicionaColunaTabela(aColunas,@nIndice,"BC_TIPO",STR0146,"cellTemplate",.T.,.T.,aLabels) //"Tipo"
    PCPMonitorUtils():AdicionaColunaTabela(aColunas,@nIndice,"BC_OPERADO",STR0141,"string",.T.) //"Operador"
    PCPMonitorUtils():AdicionaColunaTabela(aColunas,@nIndice,"BC_RECURSO",STR0059,"string",.T.) //"Recurso"    
    PCPMonitorUtils():AdicionaColunaTabela(aColunas,@nIndice,"H1_DESCRI" ,STR0073,"string",lExpResult) //"Desc. Recurso"
Return aColunas

/*/{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 StatusMotivoPerdas
    Local aRetorno := {.T.,""}

    PCPMonitorUtils():ValidaPropriedadeFilial(oFiltros["01_BC_FILIAL"],aRetorno)

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

/*/{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
@param	nTipo   , numerico   , Data final do filtro
		1 - BuscaDados (dados agrupados)
		2 - BuscaDetalhes (colunas para consulta)
@return cQuery  , caracter   , Query utilizada para busca no banco de dados
/*/
Static Function montaQuery(oFiltros, dDataIni, dDataFin, nTipo)
    Local cMotivos  := ""
    Local cProdutos := ""
    Local cQuery    := ""
    Local cRecursos := ""
    Local nIndice   := 0

    cQuery := " SELECT "
    If nTipo == 1
        cQuery +=    " SBC.BC_FILIAL, SBC.BC_MOTIVO, COUNT(SBC.BC_FILIAL) NR_APONT, SUM(SBC.BC_QUANT) QT_PERDA"
    ElseIf nTipo == 2
        cQuery +=    " SBC.BC_FILIAL, SBC.BC_TIPO, SBC.BC_MOTIVO, SBC.BC_OP, SBC.BC_OPERAC, SBC.BC_PRODUTO, SB1.B1_DESC, SB1.B1_UM,"
        cQuery +=    " SBC.BC_LOCORIG, SBC.BC_QUANT, SBC.BC_OPERADO, SBC.BC_DATA, SBC.BC_RECURSO, SB1.B1_OPERPAD, SC2.C2_ROTEIRO"
    EndIf
    cQuery += " FROM " +RetSqlName("SBC")+ " SBC "

    If nTipo == 2
        cQuery += " LEFT JOIN "+RetSqlName("SB1")+" SB1 ON SB1.B1_FILIAL = '"+xFilial("SB1",oFiltros["01_BC_FILIAL"])+"' AND SB1.B1_COD = SBC.BC_PRODUTO AND SB1.D_E_L_E_T_ = ' ' " 
        cQuery += " LEFT JOIN "+RetSqlName("SC2")+" SC2 ON SC2.C2_FILIAL = '"+xFilial("SC2",oFiltros["01_BC_FILIAL"])+"' AND SC2.C2_NUM||SC2.C2_ITEM||SC2.C2_SEQUEN||SC2.C2_ITEMGRD = SBC.BC_OP AND SC2.D_E_L_E_T_ = ' ' "
    EndIf

    cQuery += " WHERE SBC.BC_FILIAL = '"+ xFilial("SBC", oFiltros["01_BC_FILIAL"])+"' "

    If oFiltros:HasProperty("02_BC_PRODUTO") .And. ValType(oFiltros["02_BC_PRODUTO"]) == "A"
        For nIndice := 1 To Len(oFiltros["02_BC_PRODUTO"])
            If Empty(cProdutos)
                cProdutos := "'" + oFiltros["02_BC_PRODUTO"][nIndice] + "'"
            Else
                cProdutos +=  ",'" + oFiltros["02_BC_PRODUTO"][nIndice] + "'"
            EndIf
        Next nIndice
    EndIf
    If !Empty(cProdutos)
        cQuery += " AND SBC.BC_PRODUTO IN ("+cProdutos+") "
    EndIf

    If oFiltros:HasProperty("03_BC_RECURSO") .And. ValType(oFiltros["03_BC_RECURSO"]) == "A"
        For nIndice := 1 To Len(oFiltros["03_BC_RECURSO"])
            If Empty(cRecursos)
                cRecursos := "'" + oFiltros["03_BC_RECURSO"][nIndice] + "'"
            Else
                cRecursos +=  ",'" + oFiltros["03_BC_RECURSO"][nIndice] + "'"
            EndIf
        Next nIndice
    EndIf
    If !Empty(cRecursos)
        cQuery += " AND SBC.BC_RECURSO IN ("+cRecursos+") "
    EndIf

    If !Empty(oFiltros["SERIE"])
        cMotivos := "'" + IIF(oFiltros["SERIE"] <> "-",oFiltros["SERIE"],"") + "'"
    Else
        If oFiltros:HasProperty("04_BC_MOTIVO") .And. ValType(oFiltros["04_BC_MOTIVO"]) == "A"
            For nIndice := 1 To Len(oFiltros["04_BC_MOTIVO"])
                If Empty(cMotivos)
                    cMotivos := "'" + oFiltros["04_BC_MOTIVO"][nIndice] + "'"
                Else
                    cMotivos +=  ",'" + oFiltros["04_BC_MOTIVO"][nIndice] + "'"
                EndIf
            Next nIndice
        EndIf
    EndIf
    If !Empty(cMotivos)
        cQuery += " AND SBC.BC_MOTIVO IN ("+cMotivos+") "
    EndIf

    dDataFin   := dDatabase
    dDataIni   := PCPMonitorUtils():RetornaPeriodoInicial(AllTrim(oFiltros["05_TIPOPERIODO"]),dDataFin,cValToChar(oFiltros["06_PERIODO"]))

    cQuery += " AND SBC.BC_DATA BETWEEN '"+dToS(dDataIni)+"' AND '"+dToS(dDataFin)+"' "
    cQuery += " AND SBC.D_E_L_E_T_ = ' ' "

    If nTipo == 1
        cQuery +=    " GROUP BY SBC.BC_FILIAL, SBC.BC_MOTIVO"
    EndIf

    cQuery := ChangeQuery(cQuery)
Return cQuery