Expandir |
---|
| Disponibiliza uma API REST no Dashboard para visualizar um Card. Com o fonte abaixo (Exemplo) foi obtido o seguinte Card de exemplo:
Expandir |
---|
| 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.
Expandir |
---|
title | Retorno esperado para esse endpoint |
---|
| O endpoint deve retornar a seguinte estrutura json: Bloco de código |
---|
{
"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). |
Expandir |
---|
title | Retorno da API de exemplo |
---|
| { "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.
Expandir |
---|
title | Retorno esperado para esse endpoint |
---|
| O endpoint deve retornar a seguinte estrutura json: Bloco de código |
---|
{
"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. |
Expandir |
---|
title | Retorno da API de exemplo |
---|
| Bloco de código |
---|
{
"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. Expandir |
---|
title | Retorno esperado para esse endpoint |
---|
| O endpoint deve retornar a seguinte estrutura json: Bloco de código |
---|
{
"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. |
Expandir |
---|
title | Retorno da API de exemplo |
---|
| Bloco de código |
---|
{
"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.
Expandir |
---|
title | Retorno esperado para esse endpoint |
---|
| O endpoint deve retornar a seguinte estrutura json: Bloco de código |
---|
{
"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. |
Expandir |
---|
title | Retorno da API de exemplo |
---|
| Bloco de código |
---|
{
"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: "
}
]
} |
|
|
Expandir |
---|
| Clique aqui para download do fonte de exemplo. Bloco de código |
---|
| #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.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 |
|
|
Expandir |
---|
title | Serviços Gráficos de Pizza/Polar |
---|
| 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:
Expandir |
---|
| 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.
Expandir |
---|
title | Retorno esperado para esse endpoint |
---|
| O endpoint deve retornar a seguinte estrutura json: Bloco de código |
---|
{
"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. |
Expandir |
---|
title | Retorno da API de exemplo |
---|
| Bloco de código |
---|
{
"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.
Expandir |
---|
title | Retorno esperado para esse endpoint |
---|
| O endpoint deve retornar a seguinte estrutura json: Bloco de código |
---|
{
"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,
"currencyMask": [ Máscaras a serem utilizadas ]
}
]
} |
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. |
Expandir |
---|
title | Retorno da API de exemplo |
---|
| Bloco de código |
---|
{
"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",
"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 /Exemplo2/charts/itemsDetails.
Expandir |
---|
title | Retorno esperado para esse endpoint |
---|
| O endpoint deve retornar a seguinte estrutura json: Bloco de código |
---|
{
"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). |
Expandir |
---|
title | Retorno da API de exemplo |
---|
| Bloco de código |
---|
{
"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
}
|
|
|
Expandir |
---|
| Clique aqui para download do fonte de exemplo. Bloco de código |
---|
| #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 |
|
|
Expandir |
---|
title | Serviços Gráficos de Barra/Linha |
---|
| 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:
Expandir |
---|
| 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.
Expandir |
---|
title | Retorno esperado para esse endpoint |
---|
| O endpoint deve retornar a seguinte estrutura json: Bloco de código |
---|
{
"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. |
Expandir |
---|
title | Retorno da API de exemplo |
---|
| Bloco de código |
---|
{
"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.
Expandir |
---|
title | Retorno esperado para esse endpoint |
---|
| O endpoint deve retornar a seguinte estrutura json: Bloco de código |
---|
{
"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. |
Expandir |
---|
title | Retorno da API de exemplo |
---|
| Bloco de código |
---|
{
"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.
Expandir |
---|
title | Retorno esperado para esse endpoint |
---|
| O endpoint deve retornar a seguinte estrutura json: Bloco de código |
---|
{
"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). |
Expandir |
---|
title | Retorno da API de exemplo |
---|
| Bloco de código |
---|
{
"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
}
|
|
|
Expandir |
---|
| Clique aqui para download do fonte de exemplo. Bloco de código |
---|
| #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} |
|
|
Expandir |
---|
title | Serviços Gráfico de Gauge |
---|
| 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:
Expandir |
---|
| 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. Expandir |
---|
title | Retorno esperado para esse endpoint |
---|
| O endpoint deve retornar a seguinte estrutura json: Bloco de código |
---|
{
"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. |
Expandir |
---|
title | Retorno da API de exemplo |
---|
| Bloco de código |
---|
{
"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.
Expandir |
---|
title | Retorno esperado para esse endpoint |
---|
| O endpoint deve retornar a seguinte estrutura json: Bloco de código |
---|
{
"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. |
Expandir |
---|
title | Retorno da API de exemplo |
---|
| Bloco de código |
---|
{
"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.
Expandir |
---|
title | Retorno esperado para esse endpoint |
---|
| O endpoint deve retornar a seguinte estrutura json: Bloco de código |
---|
{
"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). |
Expandir |
---|
title | Retorno da API de exemplo |
---|
| Bloco de código |
---|
{
"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
}
]
} |
|
|
Expandir |
---|
| Clique aqui para download do fonte de exemplo. Bloco de código |
---|
| #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} |
|
|
Aviso |
---|
title | 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 |
|