Árvore de páginas

1. VISÃO GERAL

A classe CoreDash fornece um objeto utilizado na construção de Cards ou Gráficos.

Este objeto pode ser utilizado na construção de serviços REST utilizados no Dashboard.

02. EXEMPLO DE UTILIZAÇÃO

Exemplos de Uso

Disponibiliza uma API REST no Dashboard para visualizar um Card. Com o fonte abaixo (Exemplo) foi obtido o seguinte Card de exemplo: 

Para a disponibilização de um card, é necessário que sua API possua 4 endpoints:


1. Um POST para carregar as informações que serão apresentadas nos detalhes deste card (Opção Detalhes):

No exemplo abaixo, essas informações são retornadas pelo endpoint /CardsCustomer/cards/itemsDetails.


O endpoint deve retornar a seguinte estrutura json:

{
   "header":[
      {
         "showFilter": boolean,
         "property": string,
         "label":string
      }
   ],
   "items":[
      {
         "property": <Valor retornado pela query>,
      }
   ],
   "hasNext": boolean
}

A propriedade header refere-se ao cabeçalho da tabela. Como a tabela utilizada pelo dashboard é um componente da biblioteca PO-UI (po-table), deve-se informar as propriedades obrigatórias para este componente: property (nome identificador para a coluna) e label (título para a coluna). Para mais informações, clique aqui.

A propriedade items refere-se aos valores que serão apresentados nas colunas da tabela, ou seja, para cada propriedade informada, a query irá retornar um valor. Exemplo: { "code": "000001" }. Este deve ter a propriedade "hasNext" para informar se há próxima página (true) ou não (false).

 
{
    "header": [
        {
            "showFilter": true,
            "type": "link",
            "property": "code",
            "visible": true,
            "label": "Código",
            "action": "Link"
        },
        {
            "showFilter": true,
            "property": "store",
            "visible": true,
            "label": "Loja"
        },
        {
            "showFilter": true,
            "property": "name",
            "visible": true,
            "label": "Nome"
        },
        {
            "showFilter": true,
            "property": "fantasyName",
            "visible": true,
            "label": "Nome Fantasia"
        },
        {
            "showFilter": true,
            "property": "risk",
            "visible": true,
            "label": "Risco"
        }
    ],
    "items": [
        {
            "code": "API001",
            "store": "01",
            "name": "CLIENTE API INCLUSAO",
            "fantasyName": "CLIENTE API INCLUSAO",
            "risk": "A"
        },
        {
            "code": "API002",
            "store": "01",
            "name": "CLIENTE API ALTERACAO",
            "fantasyName": "API ALTERACAO",
            "risk": "A"
        },
        {
            "code": "API003",
            "store": "01",
            "name": "CLIENTE API EXCLUSAO",
            "fantasyName": "API EXCLUSAO",
            "risk": "A"
        },
        {
            "code": "API005",
            "store": "01",
            "name": "API 005 MANUT.COMISSAO ALTERA",
            "fantasyName": "API005",
            "risk": "A"
        },
        {
            "code": "API006",
            "store": "01",
            "name": "API006 MANUT.COMISSAO DELETA",
            "fantasyName": "API006",
            "risk": "A"
        },
        {
            "code": "API007",
            "store": "01",
            "name": "API007 - MATS030 - ALTERAR",
            "fantasyName": "API007 MATS030",
            "risk": "A"
        },
        {
            "code": "API008",
            "store": "01",
            "name": "API008 - MATS030 - DELETAR",
            "fantasyName": "API008 MATS030",
            "risk": "A"
        },
        {
            "code": "BETIM",
            "store": "01",
            "name": "LOJA BETIM",
            "fantasyName": "BETIM  MG",
            "risk": "A"
        },
        {
            "code": "C16190",
            "store": "01",
            "name": "DSERFINR-16190",
            "fantasyName": "16190",
            "risk": "A"
        },
        {
            "code": "CLIBH",
            "store": "01",
            "name": "CLIENTE BELO HORIZONTE",
            "fantasyName": "BELO HORIZONTE",
            "risk": "A"
        }
    ],
    "hasNext": true
}


2. Um GET para retornar os campos que poderão ser utilizados no filtro do card (Opção 'Filtrar' na inclusão/alteração do card):

No exemplo abaixo, essas informações são retornadas pelo endpoint /CardsCustomer/cards/cardFilter.


O endpoint deve retornar a seguinte estrutura json:

{
    "items": [
        {
            "showFilter": boolean,
            "property": string,
            "label": string
        }
    ]
}

A propriedade items refere-se ao campo "Campo" da inclusão de filtro. O property é o nome identificador para a opção e o label é o título para a opção.

 {
    "items": [
        {
            "showFilter": true,
            "property": "code",
            "label": "Código"
        },
        {
            "showFilter": true,
            "property": "store",
            "label": "Loja"
        },
        {
            "showFilter": true,
            "property": "name",
            "label": "Nome"
        },
        {
            "showFilter": true,
            "property": "fantasyName",
            "label": "Nome Fantasia"
        },
        {
            "showFilter": true,
            "property": "risk",
            "label": "Risco"
        }
    ]
}        


3. Um GET para retornar o valor das informações que serão apresentadas no card (no máximo 4). Exemplo: A informação Total clientes risco A possui o valor 197.

No exemplo abaixo, essas informações são retornadas pelo endpoint /CardsCustomer/cards/cardInfo.

O endpoint deve retornar a seguinte estrutura json:

{
    "items": [
        {
			"propriedade": "valor"
        }
    ],
    "hasNext": "false"
}

A propriedade items deve trazer todas as informações que poderão ser apresentadas no card e seu respectivo valor. No exemplo que temos acima com a informação de Total a Receber, ele se refere à propriedade "total" apresentada neste retorno.

{
    "items": [
        {
            "risco_a": 197,
            "risco_b": 10,
            "risco_c": 1
        }
    ],
    "hasNext": "false"
}


4. Um GET para retornar os campos/propriedades que podem ser utilizados na apresentação do card:

No exemplo abaixo, essas informações são retornadas pelo endpoint /CardsCustomer/cards/fieldsInfo.


O endpoint deve retornar a seguinte estrutura json:

{
    "items": [
        {
            "value": string,
            "label": string
        }
    ]
}

A propriedade items deve retornar a lista com todas as opções que podem aparecer nos campos Primeira Informação, Segunda Informação, Terceira Informação e Quarta Informação. Esse campo é um componente da biblioteca PO-ui (po-combo), portanto deve retornar as propriedades obrigatórias para sua implementação: label (título para a opção) e value (valor daquela opção). Para mais informações, clique aqui.

{
    "items": [
        {
            "value": "risco_a",
            "label": "Total clientes risco A: "
        },
        {
            "value": "risco_b",
            "label": "Total clientes risco B: "
        },
        {
            "value": "risco_c",
            "label": "Total clientes risco C: "
        }
    ]
}

Clique aqui para download do fonte de exemplo.

#INCLUDE "TOTVS.CH"
#INCLUDE "RESTFUL.CH"
 
//-------------------------------------------------------------------
/*/{Protheus.doc} WSCardsCustomer
    Exemplo de API de integração de Cards
  
    @author     Squad CRM & Faturamento
    @since      13/04/2022
    @version    12.1.33
/*/
//-------------------------------------------------------------------
WSRESTFUL CardsCustomer DESCRIPTION "Cards de Clientes"
    WSDATA Fields           AS STRING   OPTIONAL
    WSDATA Order            AS STRING   OPTIONAL
    WSDATA Page             AS INTEGER  OPTIONAL
    WSDATA PageSize         AS INTEGER  OPTIONAL
  
    WSMETHOD POST itemsDetails ;
        DESCRIPTION "Carrega os Itens Utilizados para Montagem do Painel" ;
        WSSYNTAX "/cards/itemsDetails/{Order, Page, PageSize, Fields}" ;
        PATH "/cards/itemsDetails";
        PRODUCES APPLICATION_JSON
  
    WSMETHOD GET cardFilter;
        DESCRIPTION "Disponibiliza os campos que poderão ser utilizados no filtro do Card" ;
        WSSYNTAX "/cards/cardFilter/" ;
        PATH "/cards/cardFilter";
        PRODUCES APPLICATION_JSON
  
    WSMETHOD GET cardInfo;
        DESCRIPTION "Carrega as informações do Painel" ;
        WSSYNTAX "/cards/cardInfo/" ;
        PATH "/cards/cardInfo";
        PRODUCES APPLICATION_JSON
  
    WSMETHOD GET fieldsInfo ;
        DESCRIPTION "Carrega os campos que podem que ser utilizados" ;
        WSSYNTAX "/cards/fieldsInfo/" ;
        PATH "/cards/fieldsInfo";
        PRODUCES APPLICATION_JSON
ENDWSRESTFUL
 
//-------------------------------------------------------------------
/*/{Protheus.doc} POST itemsDetails
    Carrega os Itens Utilizados para Montagem do Painel
  
    @author Squad CRM & Faturamento
    @since 13/04/2022
    @version 12.1.33
/*/
//-------------------------------------------------------------------
WSMETHOD POST itemsDetails WSRECEIVE Order, Page, PageSize, Fields WSSERVICE CardsCustomer
    Local aHeader       := {}
    Local aRet          := {}
    Local cError        := "Erro na Requisição"
    Local lRet          := .T.
    Local oCoreDash     := CoreDash():New()
    Local aFilter       := {}
    Local nQtdFilter    := 0
    Local cFilter       := ""
    Local nX            := 0
    Local cBody         := DecodeUtf8(Self:GetContent())
    Local oBody         := JsonObject():New()
    Local oJDetails     := JsonObject():New()
    Local cCampos       := ""
  
    Self:SetContentType("application/json")
  
    If !Empty(cBody)
        oBody:FromJson(cBody)
        If ValType(oBody["detailFilter"]) == "A"
            oJDetails := oBody["detailFilter"]
        EndIf
    EndIf
 
    If Len(oJDetails) == 0
        aHeader := RetHeader("SA1")
        oCoreDash:SetFields(DePara("SA1"))
        oCoreDash:SetApiQstring(Self:aQueryString)
        aFilter := oCoreDash:GetApiFilter()
        nQtdFilter := Len(aFilter)
        If nQtdFilter > 0
            For nX := 1 to nQtdFilter
                cFilter += " AND " + aFilter[nX][1]
            Next
        EndIf
 
        //Chama a função responsavel por montar a Expressão SQL
        aRet := MntQuery(, cFilter + " AND (SA1.A1_RISCO = 'A' OR SA1.A1_RISCO = 'B' OR SA1.A1_RISCO = 'C')",,"SA1")
    ElseIf Len(oJDetails) == 1
        aHeader := RetHeader("SC5")
        oCoreDash:SetFields(DePara("SC5"))
        oCoreDash:SetApiQstring(Self:aQueryString)
        aFilter := oCoreDash:GetApiFilter()
        nQtdFilter := Len(aFilter)
        If nQtdFilter > 0
            For nX := 1 to nQtdFilter
                cFilter += " AND " + aFilter[nX][1]
            Next
        EndIf
 
        cFilter := " AND SC5.C5_CLIENTE = '" + oJDetails[1]['code'] + "'"
        cCampos := "SC5.C5_NUM, SC5.C5_TIPO, SC5.C5_CONDPAG, SC5.C5_EMISSAO"
        aRet    := MntQuery(cCampos, cFilter,,"SC5")
    EndIf
  
    //Define a Query padrão utilizada no Serviço
    oCoreDash:SetQuery(aRet[1])
    oCoreDash:SetWhere(aRet[2])
    If Len(aRet) >= 3
        oCoreDash:SetGroupBy(aRet[3])
    EndIf
 
    oCoreDash:BuildJson()
    lRet := ValType(oCoreDash:GetJsonObject()['items']) == "A"
  
    If lRet
        oCoreDash:SetPOHeader(aHeader)
        Self:SetResponse( oCoreDash:ToObjectJson())
    Else
        SetRestFault(500,  EncodeUtf8(cError))
    EndIf
  
    oCoreDash:Destroy()
  
    aSize(aRet, 0)
    aSize(aHeader, 0)
Return lRet
 
//-------------------------------------------------------------------
/*/{Protheus.doc} MntQuery
    Monta a query responsável por trazer os itens utilizados no Painel
  
    @param cCampos,  Caractere, Campos que serão retornados no SELECT
    @param cFiltro,  Caractere, Filtro a ser adicionado na query
    @param cGroupBy, Caractere, Expressão group by a ser adicionada na query
    @author Squad CRM & Faturamento
    @since 13/04/2022
    @version 12.1.33
/*/
//-------------------------------------------------------------------
Static Function MntQuery(cCampos, cFiltro, cGroupBy, cTable)
    Local cQuery
    Local cWhere
    Local cGroup
 
    Default cTable := "SA1"
    Default cCampos := "SA1.A1_COD, SA1.A1_LOJA, SA1.A1_NOME, SA1.A1_NREDUZ, SA1.A1_RISCO"
  
    If cTable == "SA1"
        cQuery := " SELECT " + cCampos + " FROM " + RetSqlName("SA1") + " SA1 "
        cWhere := " SA1.R_E_C_N_O_ <= 1000 AND SA1.A1_FILIAL = '" + xFilial("SA1") + "'" + cFiltro
        cWhere += " AND SA1.D_E_L_E_T_ = ' ' "
    ElseIf cTable == "SC5"
        cQuery := " SELECT " + cCampos + " FROM " + RetSqlName("SC5") + " SC5 "
        cWhere := " SC5.C5_FILIAL = '" + xFilial("SC5") + "'" + cFiltro
        cWhere += " AND SC5.D_E_L_E_T_ = ' ' "
    EndIf
 
    If !Empty(cGroupBy)
        cGroup := cGroupBy
    EndIf
Return {cQuery, cWhere, cGroup}
 
//-------------------------------------------------------------------
/*/{Protheus.doc} DePara
    Efetua o Conversão entre os atributos objetos do Json e os campos utilizados na Consulta
  
    @author Squad CRM & Faturamento
    @since 13/04/2022
    @version 12.1.33
/*/
//-------------------------------------------------------------------
Static Function DePara(cTable)
    Local aCampos := {}
    Default cTable := "SA1"
 
    If cTable == "SA1"
        aCampos := {;
        {"code"       , "SA1.A1_COD"   },;
        {"store"      , "SA1.A1_LOJA"  },;
        {"name"       , "SA1.A1_NOME"  },;
        {"fantasyName", "SA1.A1_NREDUZ"},;
        {"risk"       , "SA1.A1_RISCO" };
        }
    ElseIf cTable == "SC5"
        aCampos := {;
        {"num"     , "SC5.C5_NUM"   },;
        {"type"    , "SC5.C5_TIPO"  },;
        {"payment" , "SC5.C5_CONDPAG"  },;
        {"emission", "SC5.C5_EMISSAO"};
        }
    EndIf
Return aCampos
 
//-------------------------------------------------------------------
/*/{Protheus.doc} GET cardInfo
    Método para retornar os dados que podem ser apresentados pelo Card
  
    @author Squad CRM & Faturamento
    @since 13/04/2022
    @version 12.1.33
/*/
//-------------------------------------------------------------------
WSMETHOD GET cardInfo WSRESTFUL CardsCustomer
    Local aFilter       := {}
    Local cWhere        := ""
    Local nFiltro       := 0
    Local oCoreDash     := CoreDash():New()
    Local oResponse     := JsonObject():New()
  
    //Converte os campos utilizados na consulta para os campos utilizados no card.
    oCoreDash:SetFields(DePara())
  
    //Converte o Filtro informado no parametro Query String.
    oCoreDash:SetApiQstring(Self:aQueryString)
    aFilter := oCoreDash:GetApiFilter()
      
    For nFiltro := 1 to Len(aFilter)
        cWhere += " AND " + aFilter[nFiltro][1]
    Next
  
    RetCardInfo(@oResponse, cWhere)
  
    self:SetResponse( EncodeUtf8(FwJsonSerialize(oResponse,.T.,.T.)) )
  
    oResponse := Nil
    FreeObj( oResponse )
  
    oCoreDash:Destroy()
    FreeObj( oCoreDash )
Return .T.
 
//-------------------------------------------------------------------
/*/{Protheus.doc} RetCardInfo
    Retorna os dados que poderão ser apresentados no painel
  
    @author Squad CRM & Faturamento
    @since 13/04/2022
    @version 12.1.33
/*/
//-------------------------------------------------------------------
Static Function RetCardInfo(oResponse, cApiFilter)
    Local oItem
    Local aItems := {}
 
    Default cApiFilter := ""
  
    oItem := JsonObject():New()
  
    oItem["risco_a"] := RetRisco(" AND SA1.A1_RISCO = 'A' " + cApiFilter)
    oItem["risco_b"] := RetRisco(" AND SA1.A1_RISCO = 'B' " + cApiFilter)
    oItem["risco_c"] := RetRisco(" AND SA1.A1_RISCO = 'C' " + cApiFilter)
    aAdd(aItems, oItem)  
  
    oResponse['hasNext'] := 'false'
    oResponse["items"] := aItems
Return Nil
 
//-------------------------------------------------------------------
/*/{Protheus.doc} RetRisco
    Retorna os dados de acordo com o filtro
  
    @param cFiltro, Caractere, Filtro a ser adicionado na query
    @author Squad CRM & Faturamento
    @since 13/04/2022
    @version 12.1.33
/*/
//-------------------------------------------------------------------
Static Function RetRisco(cFiltro)
    Local aQuery  := MntQuery("COUNT(SA1.A1_COD) TOTAL_REGISTROS", cFiltro)
    Local cQuery  := ""
    Local cTemp   := GetNextAlias()
    Local xRet  
 
    Default cWhere  := ""
    Default cInfo   := ""
 
    cQuery := aQuery[1] + " WHERE " + aQuery[2]
 
    DBUseArea( .T., "TOPCONN", TCGenQry( ,, cQuery ), cTemp, .T., .T. )
 
    xRet := (cTemp)->TOTAL_REGISTROS
 
    (cTemp)->( DBCloseArea() )
Return xRet
 
//-------------------------------------------------------------------
/*/{Protheus.doc} GET fieldsInfo
    Carrega os campos que podem que ser utilizados
  
    @author Squad CRM & Faturamento
    @since 13/04/2022
    @version 12.1.33
/*/
//-------------------------------------------------------------------
WSMETHOD GET fieldsInfo WSSERVICE CardsCustomer
    Local aItems        := {}  
    Local oResponse     :=  JsonObject():New()
    Local oCoreDash     := CoreDash():New()
  
    aAdd(aItems, { "risco_a"  , "Total clientes risco A: " })
    aAdd(aItems, { "risco_b"  , "Total clientes risco B: " })
    aAdd(aItems, { "risco_c"  , "Total clientes risco C: " })
  
    /*Retorna um Objeto no formato de Value e Label*/
    oResponse["items"] := oCoreDash:SetPOCombo(aItems)
  
    Self:SetResponse( EncodeUtf8(oResponse:ToJson()))
Return .T.
 
//-------------------------------------------------------------------
/*/{Protheus.doc} GET cardFilter
    Retorna os campos que poderão ser filtrados
  
    @author Squad CRM & Faturamento
    @since 13/04/2022
    @version 12.1.27
/*/
//-------------------------------------------------------------------
WSMETHOD GET cardFilter WSSERVICE CardsCustomer
    Local aFields       := {}
    Local oCoreDash     := CoreDash():New()
    Local oResponse     :=  JsonObject():New()
  
    aFields := {;
        {"code"       , "Código"       },;
        {"store"      , "Loja"         },;
        {"name"       , "Nome"         },;
        {"fantasyName", "Nome Fantasia"},;
        {"risk"       , "Risco"        };
        }
  
    oResponse["items"]      := oCoreDash:SetPOHeader(aFields)
  
    Self:SetResponse( EncodeUtf8(oResponse:ToJson()))
Return .T.
 
//-------------------------------------------------------------------
/*/{Protheus.doc} RetHeader
    Retorna os campos do cabeçalho dos detalhes
  
    @author Squad CRM & Faturamento
    @since 18/04/2022
    @version 12.1.33
/*/
//-------------------------------------------------------------------
Static Function RetHeader(cTable)
    Local aHeader
    Default cTable := "SA1"
 
    If cTable == "SA1"
        aHeader := {;
            {"code"       , "Código"       , 'link',,,.T.},;
            {"store"      , "Loja"         ,,,,.T.},;
            {"name"       , "Nome"         ,,,,.T.},;
            {"fantasyName", "Nome Fantasia",,,,.T.},;
            {"risk"       , "Risco"        ,,,,.T.};
            }
    ElseIf cTable == "SC5"
        aHeader := {;
            {"num"     , "Número Pedido"        ,,,,.T.},;
            {"type"    , "Tipo Pedido"          ,,,,.T.},;
            {"payment" , "Condição de Pagamento",,,,.T.},;
            {"emission", "Emissão"              ,,,,.T.};
            }
    EndIf
Return aHeader

Disponibiliza uma API REST no Dashboard para visualizar um gráfico de Pizza ou Polar. Com o fonte abaixo (Exemplo) foi obtido o seguinte Gráfico de exemplo: 

Para disponibilização de gráficos em pizza/polar, é necessário que a API possua 3 endpoints:


1. Um GET para retornar o formulário de cadastro do gráfico:

No exemplo abaixo, essas informações são retornadas pelo endpoint /Exemplo2/charts/form.

Diferente dos cards, o gráfico possui um formulário dinâmico e é o serviço acima mencionado que deve retornar os dados para a montagem do formulário de cadastro. Neste exemplo, ele nos retornou o formulário a partir da linha 'Tipo de Gráfico'. Tudo o que vem antes dessa linha, é padrão para todos os gráficos.


O endpoint deve retornar a seguinte estrutura json:

{
    "items": [
        {
            "divider": string,
            "gridSmColumns": number,
            "type": string,
            "property": string,
            "gridColumns": number,
            "required": boolean,
            "label": string
        }
    ]
}

A propriedade items deve retornar a lista com as configurações de todos os campos que devem ser apresentados no formulário. Para a montagem deste formulário, é utilizado o componente Dynamic Form do PO-ui, portanto para entender cada uma das propriedades a serem retornadas neste serviço, clique aqui.

{
    "items": [
        {
            "divider": "Tipo de Gráfico",
            "gridSmColumns": 12,
            "options": [
                {
                    "value": "pie",
                    "label": "Pizza"
                },
                {
                    "value": "polarArea",
                    "label": "Polar"
                }
            ],
            "type": "string",
            "property": "charttype",
            "gridColumns": 6,
            "required": true,
            "label": "Tipo de Gráfico"
        },
        {
            "divider": "Datas",
            "gridSmColumns": 12,
            "type": "date",
            "property": "datainicio",
            "gridColumns": 6,
            "required": true,
            "label": "Dt. Emissão De"
        },
        {
            "gridSmColumns": 12,
            "type": "date",
            "property": "datafim",
            "gridColumns": 6,
            "required": true,
            "label": "Dt. Emissão Ate"
        }
    ]
}


2. Um POST para carregar as informações do gráfico:

No exemplo abaixo, essas informações são retornadas pelo endpoint /Exemplo2/charts/retdados.


O endpoint deve retornar a seguinte estrutura json:

{
    "items": [
        {
            "chartData": [ Lista das informações a serem apresentadas no gráfico ],
            "chartLabels": [ Lista dos títulos das informações ],
            "charttype": string - Tipo do gráfico,
            "title": string - Título do gráfico
        }
    ]
}

A propriedade items deve retornar as informações do gráfico como valores a serem apresentados, títulos a representarem esses valores, título do gráfico e máscara de valores a ser utilizada.

{
    "items": [
        {
            "chartData": [
                90,
                470,
                369,
                150,
                993,
                488,
                599,
                539,
                650,
                5,
                362,
                346,
                518,
                983,
                481,
                34,
                481,
                377,
                571,
                127,
                283,
                898,
                545,
                279,
                851,
                844,
                367,
                971
            ],
            "chartLabels": [
                "AC",
                "AL",
                "AM",
                "AP",
                "BA",
                "CE",
                "DF",
                "ES",
                "EX",
                "GO",
                "MA",
                "MG",
                "MS",
                "MT",
                "PA",
                "PB",
                "PE",
                "PI",
                "PR",
                "RJ",
                "RN",
                "RO",
                "RR",
                "RS",
                "SC",
                "SE",
                "SP",
                "TO"
            ],
            "charttype": "",
            "title": "Nota fiscal por Estado"
        }
    ]
}


3. Um POST para carregar as informações que serão apresentadas nos detalhes do gráfico:

No exemplo abaixo, essas informações são retornadas pelo endpoint /Exemplo2/charts/itemsDetails.


O endpoint deve retornar a seguinte estrutura json:

{
   "header":[
      {
         "showFilter": boolean,
         "property": string,
         "label":string
      }
   ],
   "items":[
      {
         "property": <Valor retornado pela query>,
      }
   ],
   "hasNext": boolean
}

A propriedade header refere-se ao cabeçalho da tabela. Como a tabela utilizada pelo dashboard é um componente da biblioteca PO-UI (po-table), deve-se informar as propriedades obrigatórias para este componente: property (nome identificador para a coluna) e label (título para a coluna). Para mais informações, clique aqui.

A propriedade items refere-se aos valores que serão apresentados nas colunas da tabela, ou seja, para cada propriedade informada, a query irá retornar um valor. Exemplo: { "documentType": "N" }. Este deve ter a propriedade "hasNext" para informar se há próxima página (true) ou não (false).

{
    "header": [
        {
            "showFilter": true,
            "type": "link",
            "property": "document",
            "label": "Documento",
            "action": "Link"
        },
        {
            "showFilter": true,
            "property": "series",
            "label": "Serie"
        },
        {
            "showFilter": true,
            "property": "state",
            "label": "UF"
        },
        {
            "showFilter": true,
            "property": "documentType",
            "label": "Tipo"
        },
        {
            "showFilter": true,
            "property": "dateOfIssue",
            "label": "Emissão"
        }
    ],
    "items": [
        {
            "series": "004",
            "document": "000000001",
            "state": "SP",
            "documentType": "N",
            "dateOfIssue": "14/07/20"
        },
        {
            "series": "133",
            "document": "000000001",
            "state": "SP",
            "documentType": "N",
            "dateOfIssue": "10/02/21"
        },
        {
            "series": "3",
            "document": "000000001",
            "state": "SP",
            "documentType": "N",
            "dateOfIssue": "30/08/17"
        },
        {
            "series": "317",
            "document": "000000001",
            "state": "MG",
            "documentType": "N",
            "dateOfIssue": "10/06/20"
        },
        {
            "series": "626",
            "document": "000000001",
            "state": "SP",
            "documentType": "N",
            "dateOfIssue": "26/08/21"
        },
        {
            "series": "FAT",
            "document": "000000001",
            "state": "SP",
            "documentType": "N",
            "dateOfIssue": "14/10/16"
        },
        {
            "series": "MN",
            "document": "000000001",
            "state": "SP",
            "documentType": "N",
            "dateOfIssue": "02/09/21"
        },
        {
            "series": "NF",
            "document": "000000001",
            "state": "SP",
            "documentType": "N",
            "dateOfIssue": "28/03/19"
        },
        {
            "series": "3",
            "document": "000000002",
            "state": "SP",
            "documentType": "N",
            "dateOfIssue": "22/11/17"
        },
        {
            "series": "317",
            "document": "000000002",
            "state": "MG",
            "documentType": "N",
            "dateOfIssue": "10/06/20"
        }
    ],
    "hasNext": true
}           
            

Clique aqui para download do fonte de exemplo.

#INCLUDE "TOTVS.CH"
#INCLUDE "RESTFUL.CH"
 
//------------------------------------------------------------------------
/*/{Protheus.doc} Exemplo2
    Exemplo de API de integração de Graficos de Pizza e/ou Polar
 
    @author     Squad CRM & Faturamento
    @since      26/03/2020
    @version    12.1.27
/*/
//------------------------------------------------------------------------
WSRESTFUL Exemplo2 DESCRIPTION "Exemplo de API - Grafico Pizza e Polar"
 
    WSDATA JsonFilter       AS STRING   OPTIONAL
    WSDATA drillDownFilter  AS STRING   OPTIONAL
    WSDATA Page             AS INTEGER  OPTIONAL
    WSDATA PageSize         AS INTEGER  OPTIONAL
 
    WSMETHOD GET form ;
        DESCRIPTION "Form de Cadastro do Gráfico" ;
        WSSYNTAX "/charts/form/" ;
        PATH "/charts/form";
        PRODUCES APPLICATION_JSON
 
    WSMETHOD POST retdados ;
        DESCRIPTION "Retorna as Informações do Gráfico" ;
        WSSYNTAX "/charts/retdados/{JsonFilter}" ;
        PATH "/charts/retdados";
        PRODUCES APPLICATION_JSON
 
    WSMETHOD POST itemsDetails ;
        DESCRIPTION "Carrega o detalhamento do gráfico" ;
        WSSYNTAX "/charts/itemsDetails/{JsonFilter}" ;
        PATH "/charts/itemsDetails";
        PRODUCES APPLICATION_JSON
 
ENDWSRESTFUL
 
//-------------------------------------------------------------------
/*/{Protheus.doc} GET form
    Retorna os campos que apresentados no Cadastro do Grafico.
    Devera seguir o formato do Dynamic Form do PO-UI.
    https://po-ui.io/tools/dynamic-form
     
    @author Squad CRM & Faturamento
    @since 28/07/2020
    @version 12.1.27
/*/
//-------------------------------------------------------------------
WSMETHOD GET form WSSERVICE Exemplo2
 
    Local oResponse   := JsonObject():New()
    Local oCoreDash   := CoreDash():New()
 
    oCoreDash:SetPOForm("Tipo de Gráfico"    , "charttype"     , 6   , "Tipo de Gráfico"     , .T., "string",;
     oCoreDash:SetPOCombo({{"pie","Pizza"},{"polarArea","Polar"}}))
    oCoreDash:SetPOForm("Datas"              , "datainicio"      , 6   , "Dt. Emissão De"      , .T., "date")
    oCoreDash:SetPOForm(""                   , "datafim"         , 6   , "Dt. Emissão Ate"     , .T., "date")  
 
    oResponse  := oCoreDash:GetPOForm()
 
    Self:SetResponse( EncodeUtf8(oResponse:ToJson()))
 
Return .T.
 
//-------------------------------------------------------------------
/*/{Protheus.doc} POST retdados
    Retorna um objeto JSON com as informações e valores do Grafico
 
    @author Squad CRM & Faturamento
    @since 28/07/2020
    @version 12.1.27
/*/
//-------------------------------------------------------------------
WSMETHOD POST retdados WSRECEIVE JsonFilter WSSERVICE Exemplo2
 
    Local oResponse   := JsonObject():New()
    Local oCoreDash   := CoreDash():New()
    Local oJson       := JsonObject():New()
 
    oJson:FromJson(DecodeUtf8(Self:GetContent()))
 
    retDados(@oResponse, oCoreDash, oJson)
 
    Self:SetResponse( EncodeUtf8(oResponse:ToJson()))
 
    oResponse := Nil
    FreeObj( oResponse )
 
    oCoreDash:Destroy()
    FreeObj( oCoreDash )
 
Return .T.
 
//-------------------------------------------------------------------
/*/{Protheus.doc} POST retdados
    Retorna os items utilizado no Drilldown
 
    @author Squad CRM & Faturamento
    @since 28/07/2020
    @version 12.1.27
/*/
//-------------------------------------------------------------------
WSMETHOD POST itemsDetails WSRECEIVE JsonFilter, drillDownFilter WSRESTFUL Exemplo2
 
    Local aHeader     := {}
    Local aItems      := {}
    Local aRet        := {}
    Local cBody       := DecodeUtf8(Self:GetContent())
    Local cError      := "Erro na Requisição"
    Local cSelect     := ""
    Local cWhere      := ""
    Local lRet        := .T.
    Local oCoreDash  := CoreDash():New()
    Local oBody       := JsonObject():New()
    Local oJsonFilter := JsonObject():New()
    Local oJsonDD     := JsonObject():New()
 
    If !Empty(cBody)
        oBody:FromJson(cBody)
 
        If ValType(oBody["chartFilter"]) == "J"
            oJsonFilter := oBody["chartFilter"]
        EndIf
 
        If ValType(oBody["detailFilter"]) == "A"
            oJsonDD := oBody["detailFilter"]
        EndIf
    EndIf
 
    Self:SetContentType("application/json")
 
    If oJsonFilter:GetJsonText("level") == "null" .Or. Len(oJsonFilter["level"]) == 0      
        If Len(oJsonDD) == 0 //Nivel 1 do Drilldown
            aHeader := {;
                {"document"     , "Documento" ,"link"   },;
                {"series"       , "Serie"               },;
                {"state"        , "UF"                  },;
                {"documentType" , "Tipo"                },;
                {"dateOfIssue"  , "Emissão"             };
                }
 
            aItems := {;
                {"document"     , "F2_DOC"      },;
                {"series"       , "F2_SERIE"    },;
                {"state"        , "F2_EST"      },;
                {"documentType" , "F2_TIPO"     },;
                {"dateOfIssue"  , "F2_EMISSAO"  };
                }
 
            cSelect := " F2_DOC, F2_SERIE, F2_EST, F2_TIPO, F2_EMISSAO, F2_TIPO "
 
            aRet := QuerySF2(cSelect)
 
        Elseif Len(oJsonDD) == 1 //Nivel 2 do Drilldown
 
            aHeader := {;
                {"D2_ITEM"  , "Item"                            },;
                {"D2_COD"   , "Cod. Produto", "link"            },;
                {"B1_DESC"  , "Desc. Produto "                  },;
                {"D2_PRCVEN", "Vlr.Unitario", "currency","BRL"  },;
                {"D2_QUANT" , "Quantidade","number",'1.2-5'     },;
                {"D2_TOTAL" , "Vlr. Total", "currency","BRL"    },;
                {"D2_LOCAL" , "Armazem"                         };
                }
 
            aItems := {;
                {"D2_ITEM"      , "D2_ITEM"},;
                {"D2_COD"       , "D2_COD"},;
                {"B1_DESC"      , "B1_DESC"},;
                {"D2_PRCVEN"    , "D2_PRCVEN"},;
                {"D2_QUANT"     , "D2_QUANT"},;
                {"D2_TOTAL"     , "D2_TOTAL"},;
                {"D2_LOCAL"     , "D2_LOCAL"};
                }
 
            cSelect := " D2_ITEM, D2_COD, B1_DESC, D2_PRCVEN, D2_QUANT, D2_TOTAL, D2_LOCAL "
            cWhere := " D2_DOC = '" + oJsonDD[1]['document'] + "' AND D2_SERIE = '" + oJsonDD[1]['series'] + "' "
 
            aRet := QuerySD2(cSelect, cWhere)      
        Elseif Len(oJsonDD) == 2 //Nivel 3 do Drilldown
            aHeader := {;
                {"B1_COD"   , "Cod. Produto"                      },;
                {"B1_DESC"  , "Desc. Produto "                    },;
                {"B1_PRV1"  , "Preço de Venda", "currency","BRL"  },;
                {"B1_TE"    , "TES Entrada Pad"                   },;
                {"B1_TS"    , "TES Saída Pad"                     };
                }
 
            aItems := {;
                {"B1_COD"       , "B1_COD"},;
                {"B1_DESC"      , "B1_DESC"},;
                {"B1_PRV1"      , "B1_PRV1"},;
                {"B1_TE"        , "B1_TE"},;
                {"B1_TS"        , "B1_TS"};
                }
 
            cSelect := " B1_COD, B1_DESC, B1_PRV1, B1_TE, B1_TS "
            cWhere := " B1_COD = '" + oJsonDD[2]['D2_COD'] + "' "
 
            aRet := QuerySB1(cSelect, cWhere)
        Endif
    Else
        //Monta o Drilldown do grafico nivel 2
        aHeader := {;
            {"document"     , "Documento"   },;
            {"series"       , "Serie"               },;
            {"state"        , "UF"                  },;
            {"documentType" , "Tipo"                },;
            {"dateOfIssue"  , "Emissão"             };
            }
 
        aItems := {;
            {"document"     , "F2_DOC"      },;
            {"series"       , "F2_SERIE"    },;
            {"state"        , "F2_EST"      },;
            {"documentType" , "F2_TIPO"     },;
            {"dateOfIssue"  , "F2_EMISSAO"  };
            }
 
        cSelect := " F2_DOC, F2_SERIE, F2_EST, F2_TIPO, F2_EMISSAO, F2_TIPO "
 
        aRet := QuerySF2(cSelect)
    EndIf
 
    oCoreDash:SetQuery(aRet[1])
    oCoreDash:SetWhere(aRet[2])  
    oCoreDash:SetFields(aItems)
    oCoreDash:SetApiQstring(Self:aQueryString)
    oCoreDash:BuildJson()
 
    If lRet
        oCoreDash:SetPOHeader(aHeader)
        Self:SetResponse( oCoreDash:ToObjectJson() )
    Else
        cError := oCoreDash:GetJsonError()
        SetRestFault( 500,  EncodeUtf8(cError) )
    EndIf
 
    oCoreDash:Destroy()
    FreeObj(oJsonDD)
    FreeObj(oJsonFilter)
    FreeObj(oBody)
 
    aSize(aRet, 0)
    aSize(aItems, 0)
    aSize(aHeader, 0)
 
Return lRet
//-------------------------------------------------------------------
/*/{Protheus.doc} retDados
    Retorna os dados que poderão ser apresentados no Grafico
 
    @author Squad CRM & Faturamento
    @since 28/07/2020
    @version 12.1.27
/*/
//-------------------------------------------------------------------
Static Function retDados(oResponse, oCoreDash, oJson)
    Local aData     := {}
    Local aDataFim  := {}
    Local aCab      := {}
    Local aCores    := oCoreDash:GetColorChart()
    Local nLoop     := 0
 
    If oJson:GetJsonText("level") == "null" .Or. Len(oJson["level"]) == 0
        aCab := GetUF()
 
        For nLoop := 1 To Len(aCab)
            aAdd(aData, Randomize(1,999) )
        Next nLoop
 
        aDataFim := {}
        aAdd(aDataFim, oCoreDash:SetChart(aCab,aData,/*lCurrency*/,,"Nota fiscal por Estado"))
    ElseIf Len(oJson["level"]) == 1
        aCab := GetTipoNF()
 
        For nLoop := 1 To Len(aCab)
            aAdd(aData, Randomize(1,999) )
        Next nLoop
 
        aAdd(aDataFim, oCoreDash:SetChart(aCab,aData,/*lCurrency*/,"pie","Quantidade de Notas por Tipos"))
 
    ElseIf Len(oJson["level"]) == 2
        aCab := GetTopCli()
 
        For nLoop := 1 To Len(aCab)
            aAdd(aData, Randomize(1, 999) )
        Next nLoop
 
        oCoreDash:SetChartInfo( aData, 'Notas', 'bar', aCores[8][3] ) //Cor utilizada: OrangeLht
        aAdd(aDataFim, oCoreDash:SetChart(aCab,,/*lCurrency*/,"bar","TOP 10 Clientes por Tipo de Nota"))
 
    Endif
 
    oResponse["items"] := aDataFim
 
Return Nil
 
 
//-------------------------------------------------------------------
/*/{Protheus.doc} QuerySF2
    Monta a query responsável por trazer os registro da Nota fiscal
 
    @param cSelect, Caractere, Campos que serão retornados no SELECT
    @param cFilter, Caractere, Filtro complementar utilizado na clausula WHERE
    @author Squad CRM & Faturamento
    @since 28/07/2020
    @version 12.1.27
/*/
//-------------------------------------------------------------------
Static Function QuerySF2(cSelect, cFilter )
    Local cQuery
    Local cWhere
 
    Default cSelect := " SF2.F2_DOC, SF2.F2_SERIE, SF2.F2_CLIENTE, SF2.F2_LOJA, SF2.F2_TIPO "
    Default cFilter := ""
 
    cQuery := " SELECT " + cSelect + " FROM " + RetSqlName("SF2") + " SF2 "
    cWhere := " SF2.F2_FILIAL = '" + xFilial("SF2") + "' "
    If !Empty(cFilter)
        cWhere += " AND " + cFilter
    Endif
    cWhere += " AND SF2.D_E_L_E_T_ = ' ' "
 
Return { cQuery, cWhere }
 
//-------------------------------------------------------------------
/*/{Protheus.doc} QuerySD2
    Monta a query responsável por trazer os registro da Nota fiscal
 
    @param cSelect, Caractere, Campos que serão retornados no SELECT
    @param cFilter, Caractere, Filtro complementar utilizado na clausula WHERE
    @author Squad CRM & Faturamento
    @since 28/07/2020
    @version 12.1.27
/*/
//-------------------------------------------------------------------
Static Function QuerySD2(cSelect, cFilter)
    Local cQuery
    Local cWhere
 
    Default cSelect := " SD2.D2_DOC, SD2.D2_ITEM, SD2.D2_COD "
    Default cFilter := ""
 
    cQuery := " SELECT " + cSelect + " FROM " + RetSqlName("SD2") + " SD2 "
    cQuery += " INNER JOIN " + RetSqlName("SB1") + " SB1 "
    cQuery += " ON B1_COD = D2_COD AND SB1.D_E_L_E_T_ = ' ' AND B1_FILIAL = '" + xFilial("SB1") + "' "
 
    cWhere := " SD2.D2_FILIAL = '" + xFilial("SD2") + "' "
    If !Empty(cFilter)
        cWhere += " AND " + cFilter
    Endif
    cWhere += " AND SD2.D_E_L_E_T_ = ' ' "
 
Return {cQuery, cWhere}

//-------------------------------------------------------------------
/*/{Protheus.doc} QuerySB1
    Monta a query responsável por trazer o registro do Cad. Produto
 
    @param cSelect, Caractere, Campos que serão retornados no SELECT
    @param cFilter, Caractere, Filtro complementar utilizado na clausula WHERE
    @author Squad CRM & Faturamento
    @since 08/06/2022
    @version 12.1.33
/*/
//-------------------------------------------------------------------
Static Function QuerySB1(cSelect, cFilter)
    Local cQuery
    Local cWhere
 
    Default cSelect := " SB1.B1_COD, SB1.B1_DESC "
    Default cFilter := ""
 
    cQuery := " SELECT " + cSelect + " FROM " + RetSqlName("SB1") + " SB1 "
    cWhere := " SB1.B1_FILIAL = '" + xFilial("SB1") + "' "
   
    If !Empty(cFilter)
        cWhere += " AND " + cFilter
    Endif
    cWhere += " AND SB1.D_E_L_E_T_ = ' ' "
 
Return {cQuery, cWhere}
 
//-------------------------------------------------------------------
/*/{Protheus.doc} GetUF
Retorna UF
 
@author Aline Navarro
@since 22/12/2020
@version 12.1.27
/*/
//-------------------------------------------------------------------
Static Function GetUF()
 
    Local aUF       := {}
    Local aUFX5     := {}
    Local nX        := 0
    Local nLenAUFX5 := 0
 
    aUFX5 := FWGetSX5("12")
    nLenAUFX5 := Len(aUFX5)
    For nX := 1 To nLenAUFX5
        aAdd(aUF,RTrim(aUFX5[nX,3])) //X5_CHAVE
    Next nX
 
Return aUF

//-------------------------------------------------------------------
/*/{Protheus.doc} GetTipoNF
Retorna os tipos de NF
 
@author Rafael Mota Previdi
@since 08/06/2022
@version 12.1.33
/*/
//-------------------------------------------------------------------
Static Function GetTipoNF()

    Local aTipoNF := {}

    aAdd(aTipoNF, 'N=Normal')
    aAdd(aTipoNF, 'C=Compl.Preco/Quantidade')
    aAdd(aTipoNF, 'I=Compl.ICMS')
    aAdd(aTipoNF, 'P=Compl.IPI')
    aAdd(aTipoNF, 'D=Dev.Compras')
    aAdd(aTipoNF, 'B=Utiliza Fornecedor')

Return aTipoNF

Disponibiliza uma API REST no Dashboard para visualizar um gráfico de Barra ou Linha. Com o fonte abaixo foi obtido o seguinte Gráfico de exemplo: 

Para disponibilização de gráficos em barra/linha, é necessário que a API possua 3 endpoints:


1. Um GET para retornar o formulário de cadastro do gráfico:

No exemplo abaixo, essas informações são retornadas pelo endpoint /Exemplo/charts/form.

Diferente dos cards, o gráfico possui um formulário dinâmico e é o serviço que deve retornar o formulário de cadastro dele. Neste exemplo, ele nos retornou o formulário a partir da linha 'Tipo de Gráfico'. Tudo o que vem antes dessa linha, é padrão para todos os gráficos.


O endpoint deve retornar a seguinte estrutura json:

{
    "items": [
        {
            "divider": string,
            "gridSmColumns": number,
            "type": string,
            "property": string,
            "gridColumns": number,
            "required": boolean,
            "label": string
        }
    ]
}

A propriedade items deve retornar a lista com as configurações de todos os campos que devem ser apresentados no formulário. Para a montagem deste formulário, é utilizado o componente Dynamic Form do PO-ui, portanto para entender cada uma das propriedades a serem retornadas neste serviço, clique aqui.

{
    "items": [
        {
            "divider": "Tipo de Gráfico",
            "gridSmColumns": 12,
            "options": [
                {
                    "value": "line",
                    "label": "Linha"
                },
                {
                    "value": "bar",
                    "label": "Barra"
                }
            ],
            "type": "string",
            "property": "charttype",
            "gridColumns": 6,
            "required": true,
            "label": "Tipo de Gráfico"
        },
        {
            "divider": "Filtros",
            "gridSmColumns": 12,
            "type": "date",
            "property": "dateIni",
            "gridColumns": 6,
            "required": true,
            "label": "Data Inicial"
        },
        {
            "gridSmColumns": 12,
            "type": "date",
            "property": "dateFim",
            "gridColumns": 6,
            "required": true,
            "label": "Data Final"
        }
    ]
}


2. Um POST para carregar as informações do gráfico:

No exemplo abaixo, essas informações são retornadas pelo endpoint /Exemplo3/charts/retdados.


O endpoint deve retornar a seguinte estrutura json:

{
    "items": [
        {
            "chartData": [
                {
                    "data": [ Valores a serem apresentados ],
                    "fill": false,
                    "drillDown": true,
                    "backgroundColor": "rgba(255,162, 54, 1)" - Cor da linha,
                    "hoverBackgroundColor": "rgba(255,162, 54, 1)" - Cor da linha ao passar o mouse,
                    "label": string - Título que representa o conjunto de informação e que irá aparecer na legenda,
                    "lineTension": number - Tenão da curva da linha. Caso for 0, a linha será reta
                }
            ],
            "chartLabels": [ Títulos correspondentes aos valores que serão apresentados ],
            "charttype": string - Tipo de gráfico,
            "title": string - Título do gráfico,
            "chartMask": string,
            "currencyMask": [ Máscaras utilizadas para apresentar valores ]
        }
    ]
}

A propriedade items deve retornar as informações do gráfico como valores a serem apresentados, títulos a representarem esses valores, título do gráfico e máscara de valores a ser utilizada.

O gráfico utiliza a biblioteca chart.js. Para mais informações sobre suas propriedades, clique aqui.

{
    "items": [
        {
            "chartData": [
                {
                    "data": [
                        100006444,
                        100026546,
                        100015701
                    ],
                    "fill": false,
                    "drillDown": true,
                    "backgroundColor": "rgba(255,162, 54, 1)",
                    "hoverBackgroundColor": "rgba(255,162, 54, 1)",
                    "label": "Vendedor 01",
                    "lineTension": 0
                },
                {
                    "data": [
                        100009979,
                        100024524,
                        100029629
                    ],
                    "fill": false,
                    "drillDown": true,
                    "backgroundColor": "rgba(  0,178,142, 1)",
                    "hoverBackgroundColor": "rgba(  0,178,142, 1)",
                    "label": "Vendedor 02",
                    "lineTension": 0
                },
                {
                    "data": [
                        100023984,
                        100019381,
                        100026231
                    ],
                    "fill": false,
                    "drillDown": true,
                    "backgroundColor": "rgba(255,212,100, 1)",
                    "hoverBackgroundColor": "rgba(255,212,100, 1)",
                    "label": "Vendedor 03",
                    "lineTension": 0
                },
                {
                    "data": [
                        100028268,
                        100031184,
                        100010768
                    ],
                    "fill": false,
                    "drillDown": true,
                    "backgroundColor": "rgba(128,  0,  0, 1)",
                    "hoverBackgroundColor": "rgba(128,  0,  0, 1)",
                    "label": "Vendedor 04",
                    "lineTension": 0
                },
                {
                    "data": [
                        100017168.75,
                        100025408.75,
                        100020582.25
                    ],
                    "type": "line",
                    "fill": false,
                    "drillDown": false,
                    "backgroundColor": "rgba(  0,120,255, 1)",
                    "hoverBackgroundColor": "rgba(  0,120,255, 1)",
                    "label": "Média",
                    "lineTension": 0
                }
            ],
            "chartLabels": [
                "Janeiro",
                "Fevereiro",
                "Março"
            ],
            "charttype": "",
            "title": null,
            "chartMask": "currency",
            "currencyMask": [
                {
                    "maskFrac": "R$",
                    "maxiFrac": 10,
                    "miniFrac": 2
                }
            ]
        }
    ]
}


3. Um POST para carregar as informações que serão apresentadas nos detalhes do gráfico:

No exemplo abaixo, essas informações são retornadas pelo endpoint /Exemplo3/charts/itemsDetails.


O endpoint deve retornar a seguinte estrutura json:

{
   "header":[
      {
         "showFilter": boolean,
         "property": string,
         "label":string
      }
   ],
   "items":[
      {
         "property": <Valor retornado pela query>,
      }
   ],
   "hasNext": boolean
}

A propriedade header refere-se ao cabeçalho da tabela. Como a tabela utilizada pelo dashboard é um componente da biblioteca PO-UI (po-table), deve-se informar as propriedades obrigatórias para este componente: property (nome identificador para a coluna) e label (título para a coluna). Para mais informações, clique aqui.

A propriedade items refere-se aos valores que serão apresentados nas colunas da tabela, ou seja, para cada propriedade informada, a query irá retornar um valor. Exemplo: { "totalValor":  }. Este deve ter a propriedade "hasNext" para informar se há próxima página (true) ou não (false).

{
    "header": [
        {
            "showFilter": true,
            "type": "link",
            "property": "codigo",
            "label": "Código",
            "action": "Link"
        },
        {
            "showFilter": true,
            "property": "nome",
            "label": "Nome Vendedor"
        },
        {
            "showFilter": false,
            "format": "1.2-5",
            "type": "number",
            "property": "totalItens",
            "label": "Total de Itens"
        },
        {
            "showFilter": false,
            "format": "BRL",
            "type": "currency",
            "property": "totalValor",
            "label": "Valor Total"
        }
    ],
    "items": [
        {
            "totalValor": 2000,
            "totalItens": 1,
            "nome": "10% COMIS 100%EMISSAO",
            "codigo": "FIN058"
        },
        {
            "totalValor": 2000,
            "totalItens": 1,
            "nome": "10% COMISSAO 100% BAIXA   ABATE IMPOSTOS",
            "codigo": "FIN056"
        },
        {
            "totalValor": 2000,
            "totalItens": 1,
            "nome": "10% COMISSAO 100% BAIXA ABATE IMPOSTOS",
            "codigo": "FIN060"
        },
        {
            "totalValor": 2000,
            "totalItens": 1,
            "nome": "10% COMISSAO 100% EMISSAO ABATE IMPOSTOS",
            "codigo": "FIN055"
        },
        {
            "totalValor": 2000,
            "totalItens": 1,
            "nome": "10% COMISSAO 100% EMISSAO ABATE IMPOSTOS",
            "codigo": "FIN059"
        },
        {
            "totalValor": 5000,
            "totalItens": 4,
            "nome": "100% BAIXA 10%COMISSAO",
            "codigo": "FVEN10"
        },
        {
            "totalValor": 1000,
            "totalItens": 1,
            "nome": "100%baixa 0%comissao",
            "codigo": "FIN048"
        },
        {
            "totalValor": 2000,
            "totalItens": 2,
            "nome": "100%emissao 0%comissao",
            "codigo": "FIN047"
        },
        {
            "totalValor": 200000,
            "totalItens": 2,
            "nome": "5% COMISSAO 100% BAIXA",
            "codigo": "FIN600"
        },
        {
            "totalValor": 1000,
            "totalItens": 1,
            "nome": "50 50 - 10%",
            "codigo": "FIN073"
        }
    ],
    "hasNext": true
}  
            

Clique aqui para download do fonte de exemplo.

#INCLUDE "TOTVS.CH"
#INCLUDE "RESTFUL.CH"
 
//------------------------------------------------------------------------
/*/{Protheus.doc} Exemplo3
    Exemplo de API de integração de Graficos de Barra e Linha
 
    @author     Squad CRM & Faturamento
    @since      28/07/2020
    @version    12.1.27
/*/
//------------------------------------------------------------------------
WSRESTFUL Exemplo3 DESCRIPTION "Exemplo de API - Grafico Barra e Linha"
    WSDATA JsonFilter       AS STRING     OPTIONAL
    WSDATA drillDownFilter  AS STRING     OPTIONAL
    WSDATA Fields           AS STRING     OPTIONAL
    WSDATA Order            AS STRING     OPTIONAL
    WSDATA Page             AS INTEGER  OPTIONAL
    WSDATA PageSize         AS INTEGER  OPTIONAL
 
    WSMETHOD GET form ;
        DESCRIPTION "Formulario de Cadastro do Gráfico" ;
        WSSYNTAX "/charts/form/" ;
        PATH "/charts/form";
        PRODUCES APPLICATION_JSON
 
    WSMETHOD POST retDados ;
        DESCRIPTION "Deverá retornar as informações apresentadas no gráfico." ;
        WSSYNTAX "/charts/retDados/{JsonFilter}" ;
        PATH "/charts/retDados";
        PRODUCES APPLICATION_JSON
 
    WSMETHOD POST itemsDetails ;
        DESCRIPTION "Carrega o detalhamento do gráfico" ;
        WSSYNTAX "/charts/itemsDetails/{JsonFilter}" ;
        PATH "/charts/itemsDetails";
        PRODUCES APPLICATION_JSON
 
ENDWSRESTFUL
 
//-------------------------------------------------------------------
/*/{Protheus.doc} GET form
  Retorna os campos que serão apresentados no formulário.
  O padrão do campo deve seguir o Dynamic Form do Portinari.
 
  @author Squad CRM & Faturamento
  @since 27/03/2020
  @version Protheus 12.1.27
/*/
//-------------------------------------------------------------------
WSMETHOD GET form WSSERVICE Exemplo3
 
    Local oResponse   := JsonObject():New()
    Local oCoreDash   := CoreDash():New()
 
    oCoreDash:SetPOForm("Tipo de Gráfico", "charttype"       , 6, "Tipo de Gráfico"        , .T., "string" , oCoreDash:SetPOCombo({{"line","Linha"}, {"bar","Barra"}}))
    oCoreDash:SetPOForm("Filtros"        , "dateIni"         , 6, "Data Inicial"           , .T., 'date'   , , .T.)
    oCoreDash:SetPOForm(""               , "dateFim"         , 6, "Data Final"             , .T., 'date'   , , .T.)
    oCoreDash:SetPOForm(""               , "person"          , 6, "Pessoa"                 , .F., 'string' , oCoreDash:SetPOCombo({{"F","Física"}  , {"J","Jurídica"}}), .T.)
    oCoreDash:SetPOForm(""               , "blocked"         , 6, "Bloqueado?"             , .F., 'string' , oCoreDash:SetPOCombo({{"1","Sim"}     , {"2","Não"}})     , .F.)
 
    oResponse  := oCoreDash:GetPOForm()
 
    Self:SetResponse( EncodeUtf8(oResponse:ToJson()))
 
Return .T.
 
//-------------------------------------------------------------------
/*/{Protheus.doc} POST retDados
  Retorna os dados do Gráfico
 
  @author Squad CRM & Faturamento
  @since 27/03/2020
  @version Protheus 12.1.27
/*/
//-------------------------------------------------------------------
WSMETHOD POST retDados WSRECEIVE JsonFilter WSSERVICE Exemplo3
 
    Local oResponse   := JsonObject():New()
    Local oCoreDash   := CoreDash():New()
    Local oJson       := JsonObject():New()
 
    oJson:FromJson(DecodeUtf8(Self:GetContent()))
 
    retDados(@oResponse, oCoreDash, oJson)
 
    Self:SetResponse( EncodeUtf8(oResponse:ToJson()))
 
    oResponse := Nil
    FreeObj( oResponse )
 
    oCoreDash:Destroy()
    FreeObj( oCoreDash )
 
Return .T.
 
//-------------------------------------------------------------------
/*/{Protheus.doc} Function retDados
  Retorna o valor das Meta e o Valor Vendido de acordo com parâmetros
  informados
 
  @author Squad CRM & Faturamento
  @since 16/05/2022
  @version Protheus 12.1.33
/*/
//-------------------------------------------------------------------
Static Function retDados(oResponse, oCoreDash, oJson)
    Local aData    := {}
    Local aDataFim := {}
    Local aData1   := {}
    Local aData2   := {}
    Local aData3   := {}
    Local aData4   := {}
    Local aData5   := {}
    Local aCab     := {}
    Local aCores    := oCoreDash:GetColorChart()
    Local aSaldo   := {}
    Local nSaldo   := 0
    Local cPessoa  := ""
    Local cFiltros := ""
    Local nFilter  := 0
    Local nCntFilt := 0
 
    If oJson:GetJsonText("level") == "null" .Or. Len(oJson["level"]) == 0
        aCab := {'SP', 'RJ', 'MG' }



        //######### Obter os filtros do cadastro ou de usuário e aplicar na query #########
       
        // Filtro por tipo da pessoa - Com Multi-seleção
        If oJson:HasProperty("person") .And. ValType(oJson["person"]) == "A"
          cPessoa := oJson["person"]
          nCntFilt := Len(oJson["person"])
          For nFilter := 1 To nCntFilt
            If nFilter == 1
              cFiltros += " AND ("
            Else
              cFiltros += " OR "
            EndIf
           
            cFiltros += "SA1.A1_PESSOA = '" + oJson["person"][nFilter] + "' "

            If nFilter == nCntFilt
              cFiltros += ") "
            EndIf
          Next
        EndIf

        // Filtro por tipo da pessoa - com uma única seleção
        If oJson:HasProperty("blocked") .And. ValType(oJson["blocked"]) == "C"
          cFiltros += "AND SA1.A1_MSBLQL = '" + oJson["blocked"] + "'"
        EndIf

        //######### Fim da obtenção os filtros do cadastro ou de usuário e aplicar na query #########
       
        aData1 := { RetRisco(cFiltros + " AND SA1.A1_RISCO = 'A' AND SA1.A1_EST = 'SP'"), RetRisco(cFiltros + " AND SA1.A1_RISCO = 'A' AND SA1.A1_EST = 'RJ'"), RetRisco(cFiltros + " AND SA1.A1_RISCO = 'A' AND SA1.A1_EST = 'MG'") }
        aData2 := { RetRisco(cFiltros + " AND SA1.A1_RISCO = 'B' AND SA1.A1_EST = 'SP'"), RetRisco(cFiltros + " AND SA1.A1_RISCO = 'B' AND SA1.A1_EST = 'RJ'"), RetRisco(cFiltros + " AND SA1.A1_RISCO = 'B' AND SA1.A1_EST = 'MG'") }
        aData3 := { RetRisco(cFiltros + " AND SA1.A1_RISCO = 'C' AND SA1.A1_EST = 'SP'"), RetRisco(cFiltros + " AND SA1.A1_RISCO = 'C' AND SA1.A1_EST = 'RJ'"), RetRisco(cFiltros + " AND SA1.A1_RISCO = 'C' AND SA1.A1_EST = 'MG'") }
        aData4 := { RetRisco(cFiltros + " AND SA1.A1_RISCO = 'D' AND SA1.A1_EST = 'SP'"), RetRisco(cFiltros + " AND SA1.A1_RISCO = 'D' AND SA1.A1_EST = 'RJ'"), RetRisco(cFiltros + " AND SA1.A1_RISCO = 'D' AND SA1.A1_EST = 'MG'") }
 
        oCoreDash:SetChartInfo( aData1, 'Risco A', , aCores[8][3] ) //Cor utilizada: OrangeLht
        oCoreDash:SetChartInfo( aData2, 'Risco B', , aCores[1][3] ) //Cor utilizada: GreenDk
        oCoreDash:SetChartInfo( aData3, 'Risco C', , aCores[6][3] ) //Cor utilizada: YellowDk
        oCoreDash:SetChartInfo( aData4, 'Risco D', , aCores[15][3] ) //Cor utilizada: BrowDk
 
        nSaldo := (aData1[1] + aData2[1] + aData3[1] + aData4[1] ) / 4
        aAdd(aSaldo, nSaldo)
        nSaldo := (aData1[2] + aData2[2] + aData3[2] + aData4[2] ) / 4
        aAdd(aSaldo, nSaldo)
        nSaldo := (aData1[3] + aData2[3] + aData3[3] + aData4[3] ) / 4
        aAdd(aSaldo, nSaldo)
 
        oCoreDash:SetChartInfo( aSaldo, 'Média', "line", aCores[9][3] ,,.F.) //Cor utilizada: BlueDk    
 
        aDataFim := {}
        aAdd(aDataFim, oCoreDash:SetChart(aCab,,.F., ,"Quantidade de Clientes por Risco em cada Estado"))
    ElseIf Len(oJson["level"]) == 1
        aCab := {'Semana 1', 'Semana 2', 'Semana 3', 'Semana 4' }
 
        aData1          := { Randomize( 100000000.00, 999000000.00 ), Randomize( 100000000.00, 999000000.00 ), Randomize( 100000000.00, 999000000.00 ), Randomize( 100000000.00, 999000000.00 ), Randomize( 100000000.00, 999000000.00 )}
        aData2          := { Randomize( 100000000.00, 999000000.00 ), Randomize( 100000000.00, 999000000.00 ), Randomize( 100000000.00, 999000000.00 ), Randomize( 100000000.00, 999000000.00 ), Randomize( 100000000.00, 999000000.00 )}
        aData3          := { Randomize( 100000000.00, 999000000.00 ), Randomize( 100000000.00, 999000000.00 ), Randomize( 100000000.00, 999000000.00 ), Randomize( 100000000.00, 999000000.00 ), Randomize( 100000000.00, 999000000.00 )}
        aData4          := { Randomize( 100000000.00, 999000000.00 ), Randomize( 100000000.00, 999000000.00 ), Randomize( 100000000.00, 999000000.00 ), Randomize( 100000000.00, 999000000.00 ), Randomize( 100000000.00, 999000000.00 )}
        aData5          := { Randomize( 100000000.00, 999000000.00 ), Randomize( 100000000.00, 999000000.00 ), Randomize( 100000000.00, 999000000.00 ), Randomize( 100000000.00, 999000000.00 ), Randomize( 100000000.00, 999000000.00 )}
 
        oCoreDash:SetChartInfo( aData1, '00000101 - Cliente 000001',,aCores[8][3] ) //Cor utilizada: OrangeLht
        oCoreDash:SetChartInfo( aData2, '00000102 - Cliente 000002',,aCores[1][3] ) //Cor utilizada: GreenDk
        oCoreDash:SetChartInfo( aData3, '00543501 - Cliente 000003',,aCores[6][3] ) //Cor utilizada: YellowDk
        oCoreDash:SetChartInfo( aData4, '00543502 - Cliente 000004',,aCores[15][3] ) //Cor utilizada: BrowDk
        oCoreDash:SetChartInfo( aData5, '00543503 - Cliente 000005',,aCores[10][3] ) //Cor utilizada: BlueLht
 
        aDataFim := {}
        aAdd(aDataFim, oCoreDash:SetChart(aCab,,.T., ,"Maiores Vendas - " + oJson["level"][1]["labelDataSet"] + " - " + oJson["level"][1]["label"]))
    ElseIf Len(oJson["level"]) == 2
        aCab := {"Pedido - 234323", "Pedido - 234322", "Pedido - 234456", "Pedido - 234533", "Pedido - 234222" }

        oData       := JsonObject():New()
 
        aData   := { 26589, 25000,23560,10000,35000}
 
        aDataFim := {}
        aAdd(aDataFim, oCoreDash:SetChart(aCab, aData, .T.,"pie", "Maiores Clientes - " + oJson["level"][2]["labelDataSet"] + " - " + oJson["level"][1]["label"]))
    EndIf
    oResponse["items"] := aDataFim
 
Return
 
//-------------------------------------------------------------------
/*/{Protheus.doc} POST itemsDetails
  Método para retornar os dados do Painel
 
  @author Squad CRM & Faturamento
  @since 27/03/2020
  @version Protheus 12.1.27
/*/
//-------------------------------------------------------------------
WSMETHOD POST itemsDetails WSRECEIVE JsonFilter, drillDownFilter WSRESTFUL Exemplo3
 
  Local aHeader     := {}
  Local aItems      := {}
  Local aRet        := {}
  Local cBody       := DecodeUtf8(Self:GetContent())
  Local cError        := "Erro na Requisição"
  Local lRet              := .T.
  Local oCoreDash   := CoreDash():New()
  Local oBody       := JsonObject():New()
  Local oJsonFilter := JsonObject():New()
  Local oJsonDD     := JsonObject():New()
 
  If !Empty(cBody)
    oBody:FromJson(cBody)
    If ValType(oBody["chartFilter"]) == "J"
        oJsonFilter := oBody["chartFilter"]
    EndIf
    If ValType(oBody["detailFilter"]) == "A"
        oJsonDD := oBody["detailFilter"]
    EndIf
  EndIf
 
  Self:SetContentType("application/json")
  //Verifico o Nivel do grafico
  If oJsonFilter:GetJsonText("level") == "null" .Or. Len(oJsonFilter["level"]) == 0
    //Verifico o nivel do Drilldpwn
    If Len(oJsonDD) == 0
      aHeader := {;
          {"codigo"     , "Código"        ,"link"               },;
          {"nome"         , "Nome Vendedor"                       },;
          {"totalItens" , "Total de Itens","number",'1.2-5',.F. },;
          {"totalValor" , "Valor Total"   , "currency","BRL",.F.};
          }
 
      aItems := {;
          {"codigo"     , "SA3.A3_COD"    },;
          {"nome"         , "SA3.A3_NOME"   },;
          {"totalItens" , "QTDITEM"       },;
          {"totalValor" , "TOTAL","N"     };
          }
 
      aRet := MntQuery1()
    ElseIf Len(oJsonDD) == 1
      //Caso eu queira pegar o nome do nível selecionado : oJsonFilter["level"][1]["labelDataSet"]
      // Se fosse gráfico do tipo pizza: oJsonFilter["level"][1]["label"]
      aHeader := {;
          {"codigoPed"  , "Código do Pedido"    },;
          {"codigoCli"  , "Código do Cliente"   },;
          {"nome"         , "Nome"                },;
          {"totalValor" , "TOTAL","currency","BRL",.F.};
          }
 
      aItems := {;
          {"codigoPed"  , "SC5.C5_NUM"   },;
          {"codigoCli"  , "SC5.C5_CLIENTE"  },;
          {"nome"       , "SA1.A1_NOME"      },;
          {"totalValor" , "TOTAL","N"        };
          }
      aRet := MntQuery2("SC5.C5_VEND1 = '" + oJsonDD[1]["codigo"] + "'")
    EndIf
  ElseIf Len(oJsonFilter["level"]) == 1
    aHeader := {;
          {"codigoPed"  , "Código do Pedido"    },;
          {"codigoCli"  , "Código do Cliente"   },;
          {"nome"         , "Nome"                },;
          {"totalValor" , "TOTAL","currency","BRL",.F.};
          }
 
      aItems := {;
          {"codigoPed"  , "SC5.C5_NUM"   },;
          {"codigoCli"  , "SC5.C5_CLIENTE"  },;
          {"nome"       , "SA1.A1_NOME"      },;
          {"totalValor" , "TOTAL","N"        };
          }
      aRet := MntQuery2("SA1.A1_RISCO = '" + Right(oJsonFilter["level"][1]["labelDataSet"],1) + "' AND SA1.A1_EST = '" + oJsonFilter["level"][1]["label"] + "' ")
  ElseIf Len(oJsonFilter["level"]) == 2
    aHeader := {;
        {"codigo"     , "Código"        },;
        {"nome"       , "Nome Vendedor" },;
        {"totalItens" , "Total de Itens","number",'1.2-5',.F.},;
        {"totalValor" , "Valor Total", "currency","BRL",.F.};
        }
 
    aItems := {;
        {"codigo"     , "SA3.A3_COD"   },;
        {"nome"       , "SA3.A3_NOME"  },;
        {"totalItens" , "QTDITEM"      },;
        {"totalValor" , "TOTAL","N" };
        }
 
    aRet := MntQuery1()
  EndIf
 
  oCoreDash:SetQuery(aRet[1])
  oCoreDash:SetWhere(aRet[2])
  oCoreDash:SetGroupBy(aRet[3])
  oCoreDash:SetFields(aItems)
  oCoreDash:SetApiQstring(Self:aQueryString)
  oCoreDash:BuildJson()
 
  If lRet
    oCoreDash:SetPOHeader(aHeader)
    Self:SetResponse( oCoreDash:ToObjectJson() )
  Else
    cError := oCoreDash:GetJsonError()
    SetRestFault( 500,  EncodeUtf8(cError) )
  EndIf
 
  oCoreDash:Destroy()
 
  FreeObj(oBody)
  FreeObj(oJsonFilter)
  FreeObj(oJsonDD)
  FreeObj(oCoreDash)
 
  aSize(aRet, 0)
  aSize(aItems, 0)
  aSize(aHeader, 0)
 
Return( lRet )
 
//-------------------------------------------------------------------
/*/{Protheus.doc} MntQuery1
  Monta a Query o Total dos Pedidos de Venda
 
  @author Squad CRM & Faturamento
  @since 27/03/2020
  @version Protheus 12.1.27
/*/
//-------------------------------------------------------------------
Static Function MntQuery1()
  Local cQuery  := ""
  Local cWhere  := ""
  Local cGroup  := ""
   
  cQuery := " SELECT SA3.A3_COD, SA3.A3_NOME, COUNT(C6_ITEM) QTDITEM, SUM(C6_VALOR) TOTAL "
  cQuery += " FROM " + RetSqlName("SC5") + " SC5 "
 
  cQuery += " INNER JOIN " + RetSqlName("SC6") + " SC6 ON SC6.C6_NUM = SC5.C5_NUM "
  cQuery += " INNER JOIN " + RetSqlName("SA3") + " SA3 ON SA3.A3_COD = SC5.C5_VEND1 "
 
  cWhere := " SC5.D_E_L_E_T_ = ' ' "
  cWhere += " AND SC6.D_E_L_E_T_ = ' ' "
  cWhere += " AND SA3.D_E_L_E_T_ = ' ' "
  cWhere += " AND SC5.C5_FILIAL = '" + xFilial("SC5") + "'   "
  cWhere += " AND SC6.C6_FILIAL = '" + xFilial("SC6") + "'   "
  cWhere += " AND SA3.A3_FILIAL = '" + xFilial("SA3") + "'   "
  cWhere += " AND SC5.C5_EMISSAO >= '20220401'   "
 
  cGroup := " SA3.A3_COD, SA3.A3_NOME "
 
Return {cQuery, cWhere, cGroup}
 
//-------------------------------------------------------------------
/*/{Protheus.doc} MntQuery2
  Monta Query do Pedido de vendas realizando um filtro específo.
 
  @author Squad CRM & Faturamento
  @since 27/03/2020
  @version Protheus 12.1.27
/*/
//-------------------------------------------------------------------
Static Function MntQuery2(cFilter)
  Local cQuery  := ""
  Local cGroup  := ""
  Local cWhere  := ""
 
  Default cFilter := ""
 
  cQuery := " SELECT SC5.C5_NUM, SC5.C5_CLIENTE, SA1.A1_NOME, SUM(C6_VALOR) TOTAL "
  cQuery += " FROM " + RetSqlName("SC5") + " SC5 "
  cQuery += " INNER JOIN " + RetSqlName("SC6") + " SC6 ON SC6.C6_NUM = SC5.C5_NUM "
  cQuery += " INNER JOIN " + RetSqlName("SA1") + " SA1 ON SA1.A1_COD = SC5.C5_CLIENTE
 
  if !Empty(cFilter)
      cWhere += cFilter + " AND "
  EndIf
 
  cWhere += " SC5.D_E_L_E_T_ = ' ' "
  cWhere += " AND SC6.D_E_L_E_T_ = ' ' "
  cWhere += " AND SA1.D_E_L_E_T_ = ' ' "
  cWhere += " AND SC5.C5_FILIAL = '" + xFilial("SC5") + "'   "
  cWhere += " AND SC6.C6_FILIAL = '" + xFilial("SC6") + "'   "
  cWhere += " AND SA1.A1_FILIAL = '" + xFilial("SA1") + "'   "
  cWhere += " AND SC5.C5_EMISSAO >= '20220401'   "  // Limite adicionado para evitar lentidao no retorno da query em bases com uma quantidade muito grande de pedidos de vendas
 
  cGroup := " C5_NUM, C5_CLIENTE, SA1.A1_NOME "
 
Return {cQuery, cWhere, cGroup}
 
//-------------------------------------------------------------------
/*/{Protheus.doc} RetRisco
    Retorna o total de clientes de acordo com o risco informado no
    filtro
   
    @param cFiltro, Caractere, Filtro a ser adicionado na query
    @author Squad CRM & Faturamento
    @since 13/04/2022
    @version 12.1.33
/*/
//-------------------------------------------------------------------
Static Function RetRisco(cFiltro)
    Local aQuery  := MntQuery3("COUNT(SA1.A1_COD) TOTAL_REGISTROS", cFiltro)
    Local cQuery  := ""
    Local cTemp   := GetNextAlias()
    Local xRet
 
    Default cWhere  := ""
    Default cInfo   := ""
 
    cQuery := aQuery[1] + " WHERE " + aQuery[2]
 
    DBUseArea( .T., "TOPCONN", TCGenQry( ,, cQuery ), cTemp, .T., .T. )
 
    xRet := (cTemp)->TOTAL_REGISTROS
 
    (cTemp)->( DBCloseArea() )
Return xRet
 
//-------------------------------------------------------------------
/*/{Protheus.doc} MntQuery3
    Monta a query responsável por trazer os clientes de acordo com o
    risco informado no filtro
   
    @param cCampos,  Caractere, Campos que serão retornados no SELECT
    @param cFiltro,  Caractere, Filtro a ser adicionado na query
    @param cGroupBy, Caractere, Expressão group by a ser adicionada na query
    @author Squad CRM & Faturamento
    @since 13/04/2022
    @version 12.1.33
/*/
//-------------------------------------------------------------------
Static Function MntQuery3(cCampos, cFiltro, cGroupBy)
    Local cQuery
    Local cWhere
    Local cGroup
 
    Default cTable := "SA1"
    Default cCampos := "SA1.A1_COD, SA1.A1_LOJA, SA1.A1_NOME, SA1.A1_NREDUZ, SA1.A1_RISCO"
   
    cQuery := " SELECT " + cCampos + " FROM " + RetSqlName("SA1") + " SA1 "
    cWhere := " SA1.A1_FILIAL = '" + xFilial("SA1") + "'" + cFiltro
    cWhere += " AND SA1.D_E_L_E_T_ = ' ' "
 
    If !Empty(cGroupBy)
        cGroup := cGroupBy
    EndIf
Return {cQuery, cWhere, cGroup}

Disponibiliza uma API REST no Dashboard para visualizar um gráfico de Gauge. Com o fonte abaixo foi obtido o seguinte Gráfico de exemplo: 

Para disponibilização de gráficos em gauge, é necessário que a API possua 3 endpoints:


1. Um GET para retornar o formulário de cadastro do gráfico:

No exemplo abaixo, essas informações são retornadas pelo endpoint /Exemplo4/charts/form.


Diferente dos cards, o gráfico possui um formulário dinâmico e é o serviço que deve retornar o formulário de cadastro dele. Neste exemplo, ele nos retornou o formulário a partir da linha 'Tipo de Gráfico'. Tudo o que vem antes dessa linha, é padrão para todos os gráficos.

O endpoint deve retornar a seguinte estrutura json:

{
    "items": [
        {
            "divider": string,
            "gridSmColumns": number,
            "type": string,
            "property": string,
            "gridColumns": number,
            "required": boolean,
            "label": string
        }
    ]
}

A propriedade items deve retornar a lista com as configurações de todos os campos que devem ser apresentados no formulário. Para a montagem deste formulário, é utilizado o componente Dynamic Form do PO-ui, portanto para entender cada uma das propriedades a serem retornadas neste serviço, clique aqui.

{
    "items": [
        {
            "divider": "Tipo de Gráfico",
            "property": "charttype",
            "gridColumns": 6,
            "label": "Tipo de Gráfico",
            "required": true,
            "type": "string",
            "gridSmColumns": 12,
            "options": [
                {
                    "value": "gauge",
                    "label": "Gauge"
                }
            ]
        },
        {
            "divider": "Período",
            "property": "datainicio",
            "gridColumns": 6,
            "label": "Data de",
            "required": false,
            "type": "date",
            "gridSmColumns": 12
        },
        {
            "property": "datafim",
            "gridColumns": 6,
            "label": "Data até",
            "required": false,
            "type": "date",
            "gridSmColumns": 12
        }
    ]
}


2. Um POST para carregar as informações do gráfico:

No exemplo abaixo, essas informações são retornadas pelo endpoint /Exemplo4/charts/retdados.


O endpoint deve retornar a seguinte estrutura json:

{
    "items": [
        {
            "chartData": [
                {
                    <valor retornado pela query>: number
                }
            ],
            "chartLabels": [ Título correspondente ao valor que será apresentado ],
            "charttype": string - Tipo de gráfico,
            "title": string - Título do gráfico,
            "chartMask": string
        }
    ]
}

A propriedade items deve retornar as informações do gráfico como o valor a ser apresentado, título a representar esse valor, título do gráfico e máscara de valores a ser utilizada.

O gráfico utiliza o componente gauge da biblioteca PO-ui. Para mais informações sobre suas propriedades, clique aqui.

{
    "items": [
        {
            "chartLabels": [
                "Quantidade de pedidos"
            ],
            "chartData": [
                45
            ],
            "currencyMask": [
                {
                    "maskFrac": "R$",
                    "maxiFrac": 10,
                    "miniFrac": 2
                }
            ],
            "charttype": "",
            "title": null
        }
    ]
}


3. Um POST para carregar as informações que serão apresentadas nos detalhes do gráfico:

No exemplo abaixo, essas informações são retornadas pelo endpoint /Exemplo4/charts/itemsDetails.


O endpoint deve retornar a seguinte estrutura json:

{
   "header":[
      {
         "showFilter": boolean,
         "property": string,
         "label":string
      }
   ],
   "items":[
      {
         "property": <Valor retornado pela query>,
      }
   ],
   "hasNext": boolean
}

A propriedade header refere-se ao cabeçalho da tabela. Como a tabela utilizada pelo dashboard é um componente da biblioteca PO-UI (po-table), deve-se informar as propriedades obrigatórias para este componente: property (nome identificador para a coluna) e label (título para a coluna). Para mais informações, clique aqui.

A propriedade items refere-se aos valores que serão apresentados nas colunas da tabela, ou seja, para cada propriedade informada, a query irá retornar um valor. Exemplo: { "totalValor":  }. Este deve ter a propriedade "hasNext" para informar se há próxima página (true) ou não (false).

{
    "hasNext": true,
    "items": [
        {
            "C5_NUM": "CTFN40",
            "C5_CLIENTE": "FN4001",
            "C5_LOJACLI": "01",
            "C5_VEND1": ""
        },
        {
            "C5_NUM": "pcpATW",
            "C5_CLIENTE": "000001",
            "C5_LOJACLI": "01",
            "C5_VEND1": ""
        },
        {
            "C5_NUM": "pcpAU6",
            "C5_CLIENTE": "FAB004",
            "C5_LOJACLI": "01",
            "C5_VEND1": ""
        },
        {
            "C5_NUM": "PCPATR",
            "C5_CLIENTE": "COMSIR",
            "C5_LOJACLI": "01",
            "C5_VEND1": "VENDIR"
        },
        {
            "C5_NUM": "PCPATQ",
            "C5_CLIENTE": "COMSIR",
            "C5_LOJACLI": "01",
            "C5_VEND1": "VENDIR"
        },
        {
            "C5_NUM": "PCPATO",
            "C5_CLIENTE": "COMISB",
            "C5_LOJACLI": "01",
            "C5_VEND1": "ICMPIA"
        },
        {
            "C5_NUM": "PCPATH",
            "C5_CLIENTE": "COMIBX",
            "C5_LOJACLI": "01",
            "C5_VEND1": "CBX065"
        },
        {
            "C5_NUM": "MN0039",
            "C5_CLIENTE": "MN0001",
            "C5_LOJACLI": "01",
            "C5_VEND1": ""
        },
        {
            "C5_NUM": "FIN093",
            "C5_CLIENTE": "FIN462",
            "C5_LOJACLI": "01",
            "C5_VEND1": ""
        },
        {
            "C5_NUM": "FIN092",
            "C5_CLIENTE": "FIN462",
            "C5_LOJACLI": "01",
            "C5_VEND1": ""
        }
    ],
    "header": [
        {
            "property": "C5_NUM",
            "label": "Cód. Pedido ",
            "showFilter": true,
            "visible": true
        },
        {
            "property": "C5_CLIENTE",
            "label": "Cód. Cliente",
            "showFilter": true
        },
        {
            "property": "C5_LOJACLI",
            "label": "Loja Cliente",
            "showFilter": true,
            "visible": true
        },
        {
            "property": "C5_VEND1  ",
            "label": "Vendedor 1  ",
            "showFilter": true
        }
    ]
}        

Clique aqui para download do fonte de exemplo.

#INCLUDE "TOTVS.CH"
#INCLUDE "RESTFUL.CH"

//------------------------------------------------------------------------
/*/{Protheus.doc} Exemplo4
  API - Exemplo 4 - Gráfico de Gauge

  @author	Squad CRM/Faturamento
  @since	11/05/2022
  @version  12.1.33
  @return 	Json
/*/
//------------------------------------------------------------------------
WSRESTFUL Exemplo4 DESCRIPTION "Exemplo de Gráfico de Gauge"

  WSDATA JsonFilter       AS STRING	 OPTIONAL
  WSDATA drillDownFilter  AS STRING	 OPTIONAL
  WSDATA Page				      AS INTEGER OPTIONAL
  WSDATA PageSize			    AS INTEGER OPTIONAL

  WSMETHOD GET form ;
    DESCRIPTION "Carrega os campos que serão apresentados no formulário" ;
    WSSYNTAX "/charts/form/" ;
    PATH "/charts/form";
    PRODUCES APPLICATION_JSON

  WSMETHOD POST retdados ;
    DESCRIPTION "Carrega os itens" ; 
    WSSYNTAX "/charts/retdados/{JsonFilter}" ;
    PATH "/charts/retdados";
    PRODUCES APPLICATION_JSON

  WSMETHOD POST itemsDetails ;
    DESCRIPTION "Carrega os Itens Utilizados para Montagem dos detalhes" ;
    WSSYNTAX "/charts/itemsDetails/{JsonFilter}" ;
    PATH "/charts/itemsDetails";
    PRODUCES APPLICATION_JSON

ENDWSRESTFUL

//-------------------------------------------------------------------
/*/{Protheus.doc} GET form
  Retorna os campos que serão apresentados no formulário.
  O padrão do campo deve seguir o Dynamic Form do Portinari.
  
  @author Squad CRM & Faturamento
  @since 16/05/2022
  @version Protheus 12.1.33
/*/
//-------------------------------------------------------------------
WSMETHOD GET form WSSERVICE Exemplo4

  Local oResponse  := JsonObject():New()
  Local oCoreDash  := CoreDash():New()

  oCoreDash:SetPOForm("Tipo de Gráfico" , "charttype"     , 6 , "Tipo de Gráfico" ;
  , .T., "string" , oCoreDash:SetPOCombo({{"gauge","Gauge"}}))
  
  oCoreDash:SetPOForm("Período" , "datainicio"    , 6 , "Data de" ; 
  , .F., "date"   )
  
  oCoreDash:SetPOForm(""      , "datafim"       , 6 , "Data até" ;
  , .F., "date"   )

  oResponse  := oCoreDash:GetPOForm()

  Self:SetResponse( EncodeUtf8(oResponse:ToJson()))

Return .T.

//-------------------------------------------------------------------
/*/{Protheus.doc} POST retDados
  Retorna os dados do Gráfico
  
  @author Squad CRM & Faturamento
  @since 16/05/2022
  @version Protheus 12.1.33
/*/
//-------------------------------------------------------------------
WSMETHOD POST retdados WSRECEIVE JsonFilter WSSERVICE Exemplo4

  Local oResponse   := JsonObject():New()
  Local oCoreDash   := CoreDash():New()
  Local oJson       := JsonObject():New()
  Local oJsonParam  := JsonObject():New()
  Local dDataIni    := FirstYDate(dDatabase)
  Local dDataFim    := LastYDate(dDatabase)

  oJson:FromJson(DecodeUtf8(Self:GetContent()))
  
  If ValType(oJson["datainicio"]) == "C" .And. ValType(oJson["datafim"]) == "C"
    dDataIni := STOD(StrTran(oJson["datainicio"],'-',''))
    dDataFim := STOD(StrTran(oJson["datafim"],'-',''))
  Endif

  retDados(@oResponse, oCoreDash, oJson, dDataIni, dDataFim)

  Self:SetResponse( EncodeUtf8(oResponse:ToJson()))

  oResponse := Nil
  FreeObj( oResponse )

  oCoreDash:Destroy()
  FreeObj( oCoreDash )

  oJsonParam := Nil
  FreeObj(oJsonParam)

Return .T.

//-------------------------------------------------------------------
/*/{Protheus.doc} POST itemsDetails
  Método para retornar os dados detalhados por items do gráfico
  
  @author Squad CRM & Faturamento
  @since 16/05/2022
  @version Protheus 12.1.33
/*/
//-------------------------------------------------------------------
WSMETHOD POST itemsDetails WSRECEIVE JsonFilter, drillDownFilter WSRESTFUL Exemplo4

  Local aHeader     := {}
  Local aItems      := {}
  Local aRet        := {}
  Local cBody       := DecodeUtf8(Self:GetContent())
  Local cError		  := "Erro na Requisição"
  Local cSelect     := ""
  Local cFilter     := ""
  Local lRet			  := .T.
  Local oCoreDash   := CoreDash():New()
  Local oBody       := JsonObject():New()
  Local oJsonFilter := JsonObject():New()
  Local oJsonDD     := JsonObject():New()
  Local dDataIni    := FirstYDate(dDatabase)
  Local dDataFim    := LastYDate(dDatabase)

  If !Empty(cBody)
    oBody:FromJson(cBody)

    If ValType(oBody["chartFilter"]) == "J"
      oJsonFilter := oBody["chartFilter"]
      
      If ValType(oJsonFilter["datainicio"]) == "C" .And. ValType(oJsonFilter["datafim"]) == "C"
        dDataIni := STOD(StrTran(oJsonFilter["datainicio"],'-',''))
        dDataFim := STOD(StrTran(oJsonFilter["datafim"],'-',''))
      Endif
    EndIf

    If ValType(oBody["detailFilter"]) == "A"
      oJsonDD := oBody["detailFilter"]
    EndIf

  EndIf

  Self:SetContentType("application/json")

  If oJsonFilter:GetJsonText("level") == "null" .Or. Len(oJsonFilter["level"]) == 0
    If Len(oJsonDD) == 0
      aHeader := {;
        {"C5_NUM"     , "Cód. Pedido " , , , .T. , .T.   },;
        {"C5_CLIENTE" , "Cód. Cliente"                   },;
        {"C5_LOJACLI" , "Loja Cliente" , , , .T. , .T.   },;
        {"C5_VEND1  " , "Vendedor 1  "                   } ;
      }

      aItems := {;
        {"C5_NUM"     , "C5_NUM"     },;
        {"C5_CLIENTE" , "C5_CLIENTE" },;
        {"C5_LOJACLI" , "C5_LOJACLI" },;
        {"C5_VEND1"   , "C5_VEND1"   } ;
      }

      cSelect := " SC5.C5_NUM,SC5.C5_CLIENTE, SC5.C5_LOJACLI, SC5.C5_VEND1 "
      
      cFilter := "C5_EMISSAO BETWEEN '" + DTos(dDataIni) + "' AND '"+ DTos(dDataFim) + "'"
      
      aRet    := QuerySC5(cSelect, cFilter)
    
    Endif
  Endif

  oCoreDash:SetQuery(aRet[1])
  oCoreDash:SetWhere(aRet[2])
  oCoreDash:SetFields(aItems)
  oCoreDash:SetApiQstring(Self:aQueryString)
  oCoreDash:BuildJson()

	If lRet
    oCoreDash:SetPOHeader(aHeader)
		Self:SetResponse( oCoreDash:ToObjectJson() )
	Else
		cError := oCoreDash:GetJsonError()
		SetRestFault( 500,  EncodeUtf8(cError) )
	EndIf

  oCoreDash:Destroy()
  FreeObj(oJsonDD)
  FreeObj(oJsonFilter)
  FreeObj(oBody)

  aSize(aRet, 0)
  aSize(aItems, 0)
  aSize(aHeader, 0)

Return lRet

//-------------------------------------------------------------------
/*/{Protheus.doc} Function retDados
  Retorna o valor da quantidade de pedidos de acordo com parâmetros
  informados
  
  @author Squad CRM & Faturamento
  @since 16/05/2022
  @version Protheus 12.1.33
/*/
//-------------------------------------------------------------------
Static Function retDados(oResponse, oCoreDash, oJson, dDataIni, dDataFim)
  Local aData    := {}
  Local aDataFim := {}
  Local aCab     := {}

  aCab := {"Quantidade de pedidos"}

  oData   := JsonObject():New()

  aData   := { 45 /*Preencher aqui com o valor retornado pela sua query. Para o exemplo está fixo 45*/ }

  aDataFim := {}
  aAdd(aDataFim, oCoreDash:SetChart(aCab, aData))

  oResponse["items"] := aDataFim

Return Nil

//-------------------------------------------------------------------
/*/{Protheus.doc} QuerySC5
    Monta a query responsável por trazer os itens detalhados
    utilizados no gráfico
   
    @param cSelect,  Caractere, Campos que serão retornados no SELECT
    @param cFilter,  Caractere, Filtro a ser adicionado na query
    @author Squad CRM & Faturamento
    @since 16/05/2022
    @version 12.1.33
/*/
//-------------------------------------------------------------------
Static Function QuerySC5(cSelect as Char, cFilter as Char) as Array

  Local cQuery as Char
  Local cWhere as Char

  Default cSelect   := " SC5.C5_NUM,SC5.C5_CLIENTE, SC5.C5_LOJACLI,SC5.C5_VEND1 "
  Default cFilter   := ""

  cQuery := " SELECT " + cSelect + " FROM " + RetSqlName("SC5") + " SC5 "

  cWhere := " SC5.C5_FILIAL = '" + xFilial("SC5") + "' "
  If !Empty(cFilter)
    cWhere += " AND " + cFilter
  Endif

  cWhere += " AND SC5.D_E_L_E_T_ = ' ' "

Return {cQuery, cWhere}

ATENÇÃO: Regra de paginação obrigatória

Para os serviços cujo retorno solicita a propriedade "hasNext", quer dizer que eles possuem paginação. A paginação com a utilização da classe CoreDash é obrigatória e funciona através dos parâmetros page (indica a página ser retornada) e pageSize (indica quantos registros da página devem ser retornados). Seus valores default são page = 1 e pageSize = 10.

Exemplo de utilização: /Exemplo1/cards/itemsDetails?page=2&pageSize=10


03. MÉTODOS

Métodos da Classe

Sintaxe:

CoreDash():New()

Descrição:

Método construtor da classe.

Exemplo de utilização
Local oCoreDash := CoreDash():New() 

Sintaxe:

CoreDash():SetFields(aCampos)

Descrição:

Método que define os campos que serão retornados no JSON do serviço.

Parâmetros:

NomeTipoDescriçãoDefaultObrigatórioReferência
aCamposArrayArray que contém o De / Para dos campos que serão apresentados no serviço
X
Exemplo de utilização
Local oCoreDash := CoreDash():New() 
Local aCampos 	 := {} 
 
Aadd(aCampos, {"code", "A1_CODIGO"}) 
Aadd(aCampos, {"name", "A1_NOME"}) 
oCoreDash:SetFields(aCampos) 

Sintaxe:

CoreDash():SetQuery(cQuery)

Descrição:

Método que define a query que será utilizada no serviço.

Parâmetros:

NomeTipoDescriçãoDefaultObrigatórioReferência
cQueryCaractereRecebe a query que será executada. 
X
Exemplo de utilização
Local oCoreDash := CoreDash():New() 
Local cQuery 	 := "" 

cQuery := " SELECT A1_COD, A1_NOME FROM " + RetSqlName("SA1") + " SA1 "
oCoreDash:SetQuery(cQuery)

Sintaxe:

CoreDash():SetWhere(cWhere)

Descrição:

Método que define a clausula where que será no método SetQuery().

Parâmetros:

NomeTipoDescriçãoDefaultObrigatórioReferência
cWhereCaractereWhere que será utilizado na query enviada para o método SetQuery()  


Exemplo de utilização
Local oCoreDash := CoreDash():New() 
Local cQuery 	 := " SELECT A1_COD, A1_NOME FROM "+ RetSqlName("SA1") + " SA1 "
Local cWhere 	 := "" 

oCoreDash:SetQuery(cQuery)

cWhere := " SA1.D_E_L_E_T = ' ' "
oCoreDash:SetWhere(cWhere)

Sintaxe:

CoreDash():SetIndexKey(cIndexFather)

Descrição:

Método que atribui a ordenação do Alias principal.

Parâmetros:

NomeTipoDescriçãoDefaultObrigatórioReferência
cIndexFatherCaractereOrdem utilizada no alias


Exemplo de utilização
Local oCoreDash := CoreDash():New() 

//Ordenação Crescente (ASC)
oCoreDash:SetIndexKey("A1_NOME")

//Ordenação Decrescente (DESC)
oCoreDash:SetIndexKey("-A1_NOME")

Sintaxe:

CoreDash():SetGroupBy(cGroup)

Descrição:

Método responsável por definir um agrupador na query utilizada no serviço.

Parâmetros:

NomeTipoDescriçãoDefaultObrigatórioReferência
cGroupCaractere

Campos que devem compor o agrupador


X
Exemplo de utilização
Local oCoreDash := CoreDash():New() 
Local cQuery	 := " SELECT tbl.CAMPO1, tbl.CAMPO2, COUNT(1) COUNT FROM TABLE tbl "
Local cWhere	 := " WHERE FILIAL = 'valor' AND D_E_L_E_T_ = ' ' "

oCoreDash:SetQuery(cQuery)
oCoreDash:SetWhere(cWhere)
oCoreDash:SetGroupBy(" tbl.CAMPO1, tbl.CAMPO2 ")
oCoreDash:SetIndexKey("tbl.CAMPO1")

Sintaxe:

CoreDash():SetPage(nPage)

Descrição:

Método que atribui o número da página em que o usuário vai navegar.

Parâmetros:

NomeTipoDescriçãoDefaultObrigatórioReferência
nPageNuméricoNúmero da página que será apresentada para o usuário1

Exemplo de utilização
Local oCoreDash := CoreDash():New()
Local nPage 	 := 8 

oCoreDash:SetPage(nPage)

Sintaxe:

CoreDash():SetPageSize(nPageSize)

Descrição:

Método que atribui a quantidade máxima de registros que serão exibidos por página.

Parâmetros:

NomeTipoDescriçãoDefaultObrigatórioReferência
nPageSizeNuméricoQuantidade máxima de registros apresentados por página para o usuário.10

Exemplo de utilização
Local oCoreDash := CoreDash():New()
Local nPageSize	 := 20

oCoreDash:SetPageSize(nPageSize)

Sintaxe:

CoreDash():DefFields(lConvProt, cField)

Descrição:

Método que efetua a conversão entre campos do Objeto e Protheus

Parâmetros:

NomeTipoDescriçãoDefaultObrigatórioReferência
lConvProtLógicoDefine se deve converter os campos para padrão Protheus.T.

cFieldCaractereCampo que será convertido


Exemplo de utilização
Local oCoreDash := CoreDash():New()

oCoreDash:DefFields(.T.,"CAMPO")

Sintaxe:

CoreDash():GetDataType(lConvProt, cField)

Descrição:

Retorna o tipo do dado de um determinado campo.

Parâmetros:

NomeTipoDescriçãoDefaultObrigatórioReferência
lConvProtLógicoDefine se deve converter os campos para padrão Protheus.T.

cFieldCaracteresCampo que será convertido


Exemplo de utilização
Local oCoreDash := CoreDash():New()
Local dData

If oCoreDash:GetDataType(.T.,"CAMPO") == "D"
	dData := Date()
Endif

Sintaxe:

CoreDash():SetFieldsFilt(cFields) 

Descrição:

Método que define quais campos serão retornados pelo serviço.

Parâmetros:

NomeTipoDescriçãoDefaultObrigatórioReferência
cFieldsCaractereCampos que serão retornados no JSON.
X
Exemplo de utilização
Local oCoreDash := CoreDash():New()
Local cFields 	 := "order, totValue, product"

oCoreDash:SetFieldsFilt(cFields) 

Sintaxe:

CoreDash():ToObjectJson()

Descrição:

Método que retorna o JSON serializado.

Exemplo de utilização
Local oCoreDash := CoreDash():New()
Local lRet 		 := .T. 
Local cError := "Erro na requisição"
 
If lRet 
	Self:SetResponse( oCoreDash:ToObjectJson())
Else 
	cError := oCoreDash:GetJsonError() 
	SetRestFault( 500,  EncodeUtf8(cError) ) 
EndIf 

Sintaxe:

CoreDash():ToSingleObject()

Descrição:

Método que retorna um JSON serializado para apenas um objeto.

Utilizado em requisições do tipo GET que retornam informações de apenas um registro.

Exemplo de utilização
Local oCoreDash := CoreDash():New()
Local cError     := "Erro na requisição"
Local lRet 		 := .T. 
 
If lRet 
	Self:SetResponse(oCoreDash:ToSingleObject()) 
Else 
	cError := oCoreDash:GetJsonError() 
	SetRestFault( 500,  EncodeUtf8(cError) ) 
EndIf 

Sintaxe:

CoreDash():GetJsonObject()

Descrição:

Método que retorna o objeto JSON da classe

Exemplo de utilização
Local oCoreDash := CoreDash():New()
Local oJson

oJson:= oCoreDash:GetJsonObject()

If oJson["items"] != Nil
	...
Endif

Sintaxe:

CoreDash():SetApiQstring(aQueryString)

Descrição:

Método que define os campos (Retornados pelo JSON), page (página que será apresentada) e pagesize (Quantidade máxima de registros por página) e filtros.

Parâmetros:

NomeTipoDescriçãoDefaultObrigatórioReferência
aQueryStringArrayRecebe o filtro a ser utilizado quando retornado o JSON


Exemplo de utilização
Local oCoreDash 	:= CoreDash():New()
Local aQueryString 	:= {} 

aAdd(aQueryString, {"fields"	, "order, totValue"	}) 
aAdd(aQueryString, {"page"		, 10				}) 
aAdd(aQueryString, {"pagesize"	, 5					}) 

oCoreDash:SetApiQString(aQueryString) 

Sintaxe:

CoreDash():SetApiFilter(aFilter)

Descrição:

Método que atribui um filtro de pesquisa.

Parâmetros:

NomeTipoDescriçãoDefaultObrigatórioReferência
aFilterArrayArray com expressões de filtro que serão utilizadas
X
Exemplo de utilização
Local oCoreDash 	:= CoreDash():New()
Local aFilter		:= {} 

aAdd(aFilter, {"A1_COD = '000001'"}) 

oCoreDash:SetApiFilter(aFilter)

Sintaxe:

CoreDash():GetApiFilter()

Descrição:

Método que retorna o filtro de pesquisa.

Exemplo de utilização
Local oCoreDash 	:= CoreDash():New()

oCoreDash:GetApiFilter()

Sintaxe:

CoreDash():BuildJson()

Descrição:

Método que responsável por construir o objeto JSON.

Exemplo de utilização
Local oCoreDash  := CoreDash():New() 
 
Self:SetContentType("application/json") 
 
oCoreDash:SetQuery(cQuery) 
oCoreDash:SetWhere(cWhere) 
oCoreDash:SetFields(aCampos) 
oCoreDash:SetApiQstring(aQueryString) 
oCoreDash:BuildJson() 

Sintaxe:

CoreDash():SetJson(lHasNext, aItems)

Descrição:

Método que responsável por atribuir um objeto JSON, de acordo com o contrato estabelecido pela TOTVS, contento o [items] e o [hasNext].

Parâmetros:

NomeTipoDescriçãoDefaultObrigatórioReferência
lHasNextLógicoIndica se o objeto possui próxima página..T.

aItemsArrayArray com os valores do objeto.


Exemplo de utilização
Local aItems 		:= {} 
Local lHasNext 		:= .T. 
Local oCoreDash  	:= CoreDash():New() 
Local oItem 		:= JsonObject():New()
 
If (cTemp)->(Eof()) 
	lHasnext := .F. 
EndIf 
 
aAdd(aItems, oItem) 
oCoreDash:SetJson(lHasNext, aItems) 

Sintaxe:

CoreDash():SetTable(cAlias)

Descrição:

Método que recebe o alias que será responsável pela geração do JSON.

Parâmetros:

NomeTipoDescriçãoDefaultObrigatórioReferência
cAliasCaractereAlias recebido para a geração do JSON.
X
Exemplo de utilização
Local oCoreDash := CoreDash():New() 
Local cAlias 	 := GetNextAlias() 
 
oCoreDash:SetTable(cAlias) 

Sintaxe:

CoreDash():SetUpsertData(cAlias, cIndex, cBody)

Descrição:

Método que efetua a inclusão ou alteração de registros.

Parâmetros:

NomeTipoDescriçãoDefaultObrigatórioReferência
cAliasCaractereAlias recebido para a geração do JSON.
X
cIndexCaractereÍndice utilizado na busca.


cBodyCaractereJSON recebido no Body da mensagem.
X
Exemplo de utilização
Local oCoreDash := CoreDash():New() 

If oCoreDash:SetUpsertData(cAlias, Nil, cBody)
	Self:SetResponse( EncodeUtf8("Registro incluído com sucesso"))
Else
	SetRestFault( 500,  EncodeUtf8("Falha ao converter o arquivo.") )
Endif 

Sintaxe:

CoreDash():Destroy()

Descrição:

Método responsável por destruir o objeto.

Exemplo de utilização
Local oCoreDash := CoreDash():New() 

If oCoreDash:SetUpsertData(cAlias, Nil, cBody)
	Self:SetResponse( EncodeUtf8("Registro incluído com sucesso"))
Else
	SetRestFault( 500,  EncodeUtf8("Falha ao converter o arquivo.") )
Endif 

oCoreDash:Destroy()

ATENÇÃO: Método estará disponível na expedição contínua do Faturamento.

Para se utilizar deste método deve atualizar os fontes com o pacote da expedição contínua do FATURAMENTO do dia 06/05/2022.

Sintaxe:

CoreDash():GetJsonError()

Descrição:

Retorna string com a mensagem de erro do JSON.

Exemplo de utilização
Local oCoreDash := CoreDash():New() 

If oCoreDash:SetUpsertData(cAlias, Nil, cBody)
	Self:SetResponse( EncodeUtf8("Registro incluído com sucesso"))
Else
	SetRestFault( 500,  oCoreDash:GetJsonError() )
Endif 

Sintaxe:

CoreDash():SetPOHeader(aFields)

Descrição:

Método responsável por retornar um Array conforme esperado na propriedade p-columns do componente Table da biblioteca de componentes PO-UI

Parâmetros:

NomeTipoDescriçãoDefaultObrigatórioReferência
aFieldsArray

Array de até seis dimensões com os dados:

aFields[n, 1] = Property - Nome identificador (String)

aFields[n, 2] = Label - Título da coluna apresentada na tabela (String)

aFields[n, 3] = Tipo do dado - Tipos aceitos hoje: number, string, currency e link (String)

aFields[n, 4] = Formato/máscara do dado (String)

aFields[n, 5] = Indica se o campo poderá ser usado no filtro dos detalhes (String 'false' ou 'true')

aFields[n, 6] = Indica se o campo será visível na tabela (String 'false' ou 'true')


X
Exemplo de utilização
Local aFields 	 := {}
Local aItems     := {}
Local oResponse	 :=	JsonObject():New()
Local oCoreDash := CoreDash():New()

aFields := {;
            {"num"        , "Number"  , 'number', /* format */, /* showFilter */, /* visible */ },;
            {"prefixo"    , "Prefixo" , 'string', /* format */, 'false', 'false' },;
            {"parcela"    , "String"  , 'string', /* format */, /* showFilter */, /* visible */ },;
            {"valor"      , "Valor"   , 'currency', 'BRL', /* showFilter */, /* visible */ },;
            {"emissao"    , "Data"    , /* type */, /* format */, /* showFilter */, /* visible */ };
        }

aItems := oCoreDash:SetPOHeader(aFields)

oResponse["items"]      := aItems

Self:SetResponse( EncodeUtf8(oResponse:ToJson()))

Sintaxe:

CoreDash():SetPOCombo(aOptions)

Descrição:

Método responsável por retornar um Array conforme esperado na propriedade p-options do componente Combo da biblioteca de componentes PO-UI.

Parâmetros:

NomeTipoDescriçãoDefaultObrigatórioReferência
aOptionsArray

Array de duas dimensões com as seguintes informações:

aOptions[n, 1] = Valor (Value)

aOptions[n, 2] = Rotulo (Label)


X
Exemplo de utilização
Local oCoreDash := CoreDash():New() 
Local aOptions	 := {}

aAdd(aOptions, {"phone"		,"Telefono"	})
aAdd(aOptions, {"cellPhone"	,"Celular"	})

oCoreDash:SetPOCombo(aOptions)

Sintaxe:

CoreDash():SetPOForm(cDivider, cProperty, cGridColumns, cLabel, lRequired, cType, aOptions, loptionsMulti)

Descrição:

Método responsável por construir um Formulário utilizando como base o componente DynamicForm do da biblioteca da PO-UI.

Parâmetros:

NomeTipoDescriçãoDefaultObrigatórioReferência
cDividerCaractere

Cria uma divisória entre os campos, utilizando o nome definido na propriedade cDivider.




cPropertyCaractereNome da Propriedade.


cGridColumnsCaractere

Número de Colunas Ocupado pelo Campo.




cLabelCaractereRotulo/Label do Campo.


lRequiredLógicoDefine se o campo é obrigatório.


cTypeCaractereTipo do Campo.


aOptionsArrayLista de opções do campo.


loptionsMultiCaractereDefine se o campo é MultSelect.


Exemplo de utilização
Local oResponse   := JsonObject():New()
Local oCoreDash  := CoreDash():New()

oCoreDash:SetPOForm("Tipo de Gráfico", "graphictype"     , 6  , "Tipo de Gráfico"    , .T., "string", oCoreDash:SetPOCombo({{"pie","Pizza"},{"polarArea","Radar"}}))
oCoreDash:SetPOForm("Filtros"        , "typesearchcombo" , 12 , "Tipo de Pesquisa"   , .T., "string", oCoreDash:SetPOCombo({{"mensal","Mensal"},{"anual","Anual"}}))
oCoreDash:SetPOForm(""               , "datadereferencia", 6  , "Data de Referência" , .T., "date")

oResponse  := oCoreDash:GetPOForm()

Self:SetResponse( EncodeUtf8(oResponse:ToJson()))

Sintaxe:

CoreDash():GetPOForm()

Descrição:

Método responsável por retornar o Formulário, construído através do método SetPOForm.

Exemplo de utilização
Local oResponse   := JsonObject():New()
Local oCoreDash  := CoreDash():New()

oCoreDash:SetPOForm("Tipo de Gráfico", "graphictype"     , 6  , "Tipo de Gráfico"    , .T., "string", oCoreDash:SetPOCombo({{"pie","Pizza"},{"polarArea","Radar"}}))
oCoreDash:SetPOForm("Filtros"        , "typesearchcombo" , 12 , "Tipo de Pesquisa"   , .T., "string", oCoreDash:SetPOCombo({{"mensal","Mensal"},{"anual","Anual"}}))
oCoreDash:SetPOForm(""               , "datadereferencia", 6  , "Data de Referência" , .T., "date")

oResponse  := oCoreDash:GetPOForm()

Self:SetResponse( EncodeUtf8(oResponse:ToJson()))

Sintaxe:

CoreDash():SetChartInfo(aDados, cLegenda, cTipo, cBgColor, lBackGround, lDrillDown)

Descrição:

Método responsável por adicionar linhas e/ou colunas em um Gráfico de Barra ou Linha.

Parâmetros:

NomeTipoDescriçãoDefaultObrigatórioReferência
aDadosCaractere

Array de Valores utilizados no gráfico.


X
cLegendaCaractereLegenda Label da série do gráfico.
X
cTipoCaractere

Tipo da série no gráfico. Exemplos: bar, line




cBgColorCaractereCor da série.


lBackGroundLógicoDefine se o gráfico de linhas terá cor de fundo..F.

lDrillDownCaractereDefine se a série permite drilldown..T.

Exemplo de utilização
Local oCoreDash  := CoreDash():New()
Local aHeader	  := {"2019","2020","2021"}
Local aData1	  := { Randomize(1,99), Randomize(1,99), Randomize(1,99) }
Local aData2	  := { Randomize(1,99), Randomize(1,99), Randomize(1,99) }
Local aSaldo	  := {}
Local nSaldo	  := 0

oCoreDash:SetChartInfo( aData1, 'Vendedor 01' )
oCoreDash:SetChartInfo( aData2, 'Vendedor 02' )

nSaldo := aData1[1] + aData2[1]
aAdd(aSaldo, nSaldo)
nSaldo := aData1[2] + aData2[2]
aAdd(aSaldo, nSaldo)
nSaldo := aData1[3] + aData2[3]
aAdd(aSaldo, nSaldo)

oCoreDash:SetChartInfo( aSaldo, "Média", "line", "rgba(255,240,210,0.0)", .F., .F.)

Sintaxe:

CoreDash():GetChartInfo()

Descrição:

Método responsável por retornar todos os gráficos adicionados através do método SetChartInfo.

Exemplo de utilização
Local aGraphic 	  := {}
Local oCoreDash  := CoreDash():New()

oCoreDash:SetChartInfo( aSaldo, "Média", "line", "rgba(23,132,175,0.59)", .F., .F.)
aGraphic := oCoreDash:GetChartInfo()

Sintaxe:

CoreDash():SetChart( aLegenda, aDados, lCurrency, cType, cTitle, aMaskFrac ) Class CoreDash

Descrição:

Método responsável por retornar todas as informações de gráficos de Barra/Linha.

Parâmetros:

NomeTipoDescriçãoDefaultObrigatórioReferência
aLegendaArrayLegendas apresentadas no Gráfico
X
aDadosArray

Dados impressos no Gráfico.

Observação: Para gráficos do tipo barra/linha, pode se usar o próprio GetChartInfo




lCurrencyLógicoInforma se a máscara retornada será ou não do tipo moeda.F.

cTypeCaractereTipo de Gráfico que será retornado.


cTitleCaractereTítulo apresentado no Gráfico.


aMaskFracArrayInforma os formatos de máscara que podem ser passados 


Atenção

Para os gráficos do tipo Pizza e Polar não é possível realizar a máscara monetária através dos parâmetros lCurrency e aMaskFrac.

Exemplo de utilização
Local oCoreDash := CoreDash():New()
Local aData     := {}
Local aCab      := {}
Local lCurrency := .T.
Local aItem 	:= {}
Local aMask 	:= {}
Local cType 	:= "bar"

aMask   := JsonObject():New()
aItem['maskFrac'] := "R$"
aItem['maxiFrac'] := 10
aItem['miniFrac'] := 2
AAdd(aMask,aItem)

oCoreDash:SetChart(aCab,aData,lCurrency,cType,"Nota fiscal por Estado",aMask)
  

Sintaxe:

CoreDash():GetCposLGPD()

Descrição:

Método responsável por retornar array com os campos sensíveis que deverão ter exibição restrita de acordo com o Usuário logado.

Exemplo de utilização
Local oCoreDash := CoreDash():New() 
Local aCampos 	:= {}
Local aCposLGPD	:= {} 
 
Aadd(aCampos, {"code", "A1_CODIGO"}) 
Aadd(aCampos, {"name", "A1_NOME"}) 

oCoreDash:SetFields(aCampos) 

aCposLGPD := oCoreDash:GetCposLGPD()

Sintaxe:

CoreDash():GetColorChart()

Descrição:

Método responsável por retornar em um array todas as cores padronizadas para uso de gráficos DASH.

Se for passado ao metodo o ID da cor, será retornado somente a cor solicitada.

CoreDash():GetColorChart(X);

Onde X é o ID da cor solicitada.

Parâmetros:

Cor (Variável)Descrição da CorIDCódigo RGBAPosição ArrayExemplo Cor
cGreenDkVerde Escuro1rgba( 0,178,142, 1)aArray[1][3]

cGreenLhtVerde Claro2

rgba( 0,201,161, 1)

aArray[2][3]

cRedDkVermelho Escuro3rgba(198, 72, 64, 1)aArray[3][3]

cRedLhtVermelho Claro4rgba(227, 73, 64, 1)aArray[4][3]

cYellDkAmarelo Escuro5rgba(252,203, 76, 1)aArray[5][3]

cYellLhtAmarelo Claro6rgba(255,212,100, 1)aArray[6][3]

cOrangeDkLaranja Escuro7rgba(234,155, 62, 1)aArray[7][3]

cOrangeLhtLaranja Claro8rgba(255,162, 54, 1)aArray[8][3]

cBlueDkAzul Escuro9rgba( 0,120,255, 1)aArray[9][3]

cBlueLhtAzul Claro10rgba( 50,165,255, 1)aArray[10][3]

cGreyDkCinza Escuro11rgba(192,192,192, 1)aArray[11][3]

cGreyLhtCinza Claro12rgba(200,200,210, 1)aArray[12][3]

cPurpleDkRoxo Escuro13rgba(128, 0,128, 1)aArray[13][3]

cPurpleLhtRoxo Claro14rgba(185, 35,185, 1)aArray[14][3]

cBrownDkMarron Escuro15rgba(128, 0, 0, 1)aArray[15][3]

cBrownLhtMarron Claro16rgba(160, 80, 40, 1)aArray[16][3]

cFuchsiaDkPink Escuro17rgba(255, 0,255, 1)aArray[17][3]

cFuchsiaLhtPink Claro18rgba(255,120,255, 1)aArray[18][3]

cMnightBlueAzul Meia Noite19rgba( 25, 25,112, 1)aArray[19][3]

cMediumBlueAzul Médio20rgba( 0, 0,205, 1)aArray[20][3]

cDGreenVerde21rgba( 0,100, 0, 1)aArray[21][3]

cFGreenVerde Floresta22rgba( 34,139, 34, 1)aArray[22][3]

cGreenYelVerde Limão23rgba(173,255, 47, 1)aArray[23][3]

cSalmonSalmão24rgba(250,128,114, 1)aArray[24][3]

cTanRosa Queimado25rgba(210,180,140, 1)aArray[25][3]

cWheatRosa Trigo26rgba(245,222,179, 1)aArray[26][3]

cSlateGrayCinza Ardósia27rgba(112,128,144, 1)aArray[27][3]

cMistyRoseRosa Claro28rgba(255,228,225, 1)aArray[28][3]

04. DEMAIS INFORMAÇÕES

  • Não há.