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: "
}
]
} |
|
|
|
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,
"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. |
{
"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. 
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
}
|
|
|
#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} |
|
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 |
|