1. VISIÓN GENERAL

La clase CoreDash ofrece un objeto utilizado en la construcción de Cards o Gráficos.

Este objeto puede utilizarse en la construcción de servicios REST utilizados en el Dashboard.

02. EJEMPLO DE UTILIZACIÓN

Exemplos de Uso

Servicio Cards

Pone a disposición una API REST en el Dashboard para visualizar un Card. Con el siguiente fuente (Ejemplo) se obtuvo el siguiente Card de ejemplo: 

Para poner a disposición un card, es necesario que su API tenga 4 endpoints:


1. Un POST para cargar las informaciones que se mostrarán en los detalles de este card (Opción Detalles):

En el siguiente ejemplo, estas informaciones son devueltas por el endpoint /CardsCustomer/cards/itemsDetails.


El endpoint debe devolver la siguiente estructura json:

{
   "header":[
      {
         "showFilter": boolean,
         "property": string,
         "label":string
      }
   ],
   "items":[
      {
         "property": <Valor devuelto por la query>,
      }
   ],
   "hasNext": boolean
}

La propiedad header se refiere al encabezado de la tabla. Como la tabla utilizada por el dashboard es un componente de la biblioteca PO-UI (po-table), deben informarse las propiedades obligatorias a este componente: property (nombre identificador para la columna) y label (título para la columna). Para más informaciones, haga clic aquí.

La propiedad ítems se refiere a los valores que se mostrarán en las columnas de la tabla, es decir, para cada propiedad informada, la query devolverá un valor. Ejemplo: { "code": "000001" }. Este debe tener la propiedad "hasNext" para informar si existe una próxima página (true) o no (false).

 
{
    "header": [
        {
            "showFilter": true,
            "type": "link",
            "property": "code",
            "visible": true,
            "label": "Código",
            "action": "Enlace"
        },
        {
            "showFilter": true,
            "property": "store",
            "visible": true,
            "label": "Tienda"
        },
        {
            "showFilter": true,
            "property": "name",
            "visible": true,
            "label": "Nombre"
        },
        {
            "showFilter": true,
            "property": "fantasyName",
            "visible": true,
            "label": "Nombre fantasía"
        },
        {
            "showFilter": true,
            "property": "risk",
            "visible": true,
            "label": "Riesgo"
        }
    ],
    "items": [
        {
            "code": "API001",
            "store": "01",
            "name": "CLIENTE API INCLUSIÓN",
            "fantasyName": "CLIENTE API INCLUSIÓN",
            "risk": "A"
        },
        {
            "code": "API002",
            "store": "01",
            "name": "CLIENTE API MODIFICACIÓN",
            "fantasyName": "API MODIFICACIÓN",
            "risk": "A"
        },
        {
            "code": "API003",
            "store": "01",
            "name": "CLIENTE API BORRADO",
            "fantasyName": "API BORRADO",
            "risk": "A"
        },
        {
            "code": "API005",
            "store": "01",
            "name": "API 005 MANUT.COMISIÓN MODIFICA",
            "fantasyName": "API005",
            "risk": "A"
        },
        {
            "code": "API006",
            "store": "01",
            "name": "API006 MANUT.COMISIÓN BORRA",
            "fantasyName": "API006",
            "risk": "A"
        },
        {
            "code": "API007",
            "store": "01",
            "name": "API007 - MATS030 - MODIFICAR",
            "fantasyName": "API007 MATS030",
            "risk": "A"
        },
        {
            "code": "API008",
            "store": "01",
            "name": "API008 - MATS030 - BORRAR",
            "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. Un GET para devolver los campos que pueden utilizarse en el filtro del card (Opción 'Filtrar' en la inclusión/modificación del card):

En el siguiente ejemplo, estas informaciones son devueltas por el endpoint /CardsCustomer/cards/cardFilter.


El endpoint debe devolver la siguiente estructura json:

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

La propiedad ítems se refiere al campo "Campo" de la inclusión de filtro. El property es el nombre identificador para la opción y el label es el título para la opción.

 {
    "items": [
        {
            "showFilter": true,
            "property": "code",
            "label": "Código"
        },
        {
            "showFilter": true,
            "property": "store",
            "label": "Tienda"
        },
        {
            "showFilter": true,
            "property": "name",
            "label": "Nombre"
        },
        {
            "showFilter": true,
            "property": "fantasyName",
            "label": "Nombre fantasía"
        },
        {
            "showFilter": true,
            "property": "risk",
            "label": "Riesgo"
        }
    ]
}        


3. Un GET para devolver el valor de las informaciones que se mostrarán en el card (como máximo 4). Ejemplo: La información Total clientes riesgo A tiene el valor 197.

En el siguiente ejemplo, estas informaciones son devueltas por el endpoint /CardsCustomer/cards/cardInfo.

El endpoint debe devolver la siguiente estructura json:

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

La propiedad ítems debe traer todas las informaciones que podrán mostrarse en el card y su respectivo valor. En el ejemplo que tenemos anteriormente con la información de Total por cobrar, este se refiere a la propiedad "total" mostrada en esta devolución.

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


4. Un GET para devolver los campos/propiedades que pueden utilizarse en la presentación del card:

En el siguiente ejemplo, estas informaciones son devueltas por el endpoint /CardsCustomer/cards/fieldsInfo.


El endpoint debe devolver la siguiente estructura json:

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

La propiedad ítems debe devolver la lista con todas las opciones que pueden aparecer en los campos Primera información, Segunda información, Tercera información y Cuarta información. Este campo es un componente de la biblioteca PO-ui (po-combo), por lo tanto, debe devolver las propiedades obligatorias para su implementación: label (título para la opción) y value (valor de aquella opción). Para más informaciones, haga clic aquí.

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

Ejemplo

Haga clic aquí para download del fuente de ejemplo.

#INCLUDE "TOTVS.CH"
#INCLUDE "RESTFUL.CH"
 
//-------------------------------------------------------------------
/*/{Protheus.doc} WSCardsCustomer
    Ejemplo de API de integración de Cards
  
    @author     Squad CRM & Facturación
    @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 "Activa los ítems utilizados para montaje del panel" ;
        WSSYNTAX "/cards/itemsDetails/{Order, Page, PageSize, Fields}" ;
        PATH "/cards/itemsDetails";
        PRODUCES APPLICATION_JSON
  
    WSMETHOD GET cardFilter;
        DESCRIPTION "Pone a disposición los campos que podrán utilizarse en el filtro del Card" ;
        WSSYNTAX "/cards/cardFilter/" ;
        PATH "/cards/cardFilter";
        PRODUCES APPLICATION_JSON
  
    WSMETHOD GET cardInfo;
        DESCRIPTION "Activa las informaciones del panel" ;
        WSSYNTAX "/cards/cardInfo/" ;
        PATH "/cards/cardInfo";
        PRODUCES APPLICATION_JSON
  
    WSMETHOD GET fieldsInfo ;
        DESCRIPTION "Activa los campos que pueden utilizarse" ;
        WSSYNTAX "/cards/fieldsInfo/" ;
        PATH "/cards/fieldsInfo";
        PRODUCES APPLICATION_JSON
ENDWSRESTFUL
 
//-------------------------------------------------------------------
/*/{Protheus.doc} POST itemsDetails
    Activa los ítems utilizados para montaje del panel
  
    @author Squad CRM & Facturación
    @since 13/04/2022
    @version 12.1.33
/*/
//-------------------------------------------------------------------
WSMETHOD POST itemsDetails WSRECEIVE Order, Page, PageSize, Fields WSSERVICE CardsCustomer
    Local aHeader       := {}
    Local aRet          := {}
    Local cError        := "Error en la requisición"
    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
 
        //Activa la función responsable por montar la expresión 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 la query estándar utilizada en el servicio
    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 la query responsable por traer los ítems utilizados en el panel
  
    @param cCampos,  Carácter, Campos que se devolverán en el SELECT
    @param cFiltro,  Carácter, Filtro que se incluirá en la query
    @param cGroupBy, Carácter, Expresión group by que se incluirá en la query
    @author Squad CRM & Facturación
    @since 13/04/2022
    @version 12.1.33
/*/
//-------------------------------------------------------------------
Static Function MntQuery(cCampos, cFiltro, cGroupBy, cTable)
    Local cQuery
    Local cWhere
    Local cGroup
 
    Default cTable := "SA1"
    Default cCampos := "SA1.A1_COD, SA1.A1_LOJA, SA1.A1_NOME, SA1.A1_NREDUZ, SA1.A1_RISCO"
  
    If cTable == "SA1"
        cQuery := " SELECT " + cCampos + " FROM " + RetSqlName("SA1") + " SA1 "
        cWhere := " SA1.R_E_C_N_O_ <= 1000 AND SA1.A1_FILIAL = '" + xFilial("SA1") + "'" + cFiltro
        cWhere += " AND SA1.D_E_L_E_T_ = ' ' "
    ElseIf cTable == "SC5"
        cQuery := " SELECT " + cCampos + " FROM " + RetSqlName("SC5") + " SC5 "
        cWhere := " SC5.C5_FILIAL = '" + xFilial("SC5") + "'" + cFiltro
        cWhere += " AND SC5.D_E_L_E_T_ = ' ' "
    EndIf
 
    If !Empty(cGroupBy)
        cGroup := cGroupBy
    EndIf
Return {cQuery, cWhere, cGroup}
 
//-------------------------------------------------------------------
/*/{Protheus.doc} DePara
    Efectúa la conversión entre los atributos objetos del Json y los campos utilizados en la Consulta
  
    @author Squad CRM & Facturación
    @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 devolver los datos que pueden mostrarse por el Card
  
    @author Squad CRM & Facturación
    @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()
  
    //Convierte los campos utilizados en la consulta a los campos utilizados en el card.
    oCoreDash:SetFields(DePara())
  
    //Converte el filtro informado en el parámetro 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
    Devuelve los datos que podrán mostrarse en el panel
  
    @author Squad CRM & Facturación
    @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
    Devuelve los datos de acuerdo con el filtro
  
    @param cFiltro, Carácter, Filtro que se incluirá en la query
    @author Squad CRM & Facturación
    @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
    Activa los campos que pueden utilizarse
  
    @author Squad CRM & Facturación
    @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 riesgo A: " })
    aAdd(aItems, { "risco_b"  , "Total clientes riesgo B: " })
    aAdd(aItems, { "risco_c"  , "Total clientes riesgo C: " })
  
    /*Devuelve un objeto en el formato de Value y Label*/
    oResponse["items"] := oCoreDash:SetPOCombo(aItems)
  
    Self:SetResponse( EncodeUtf8(oResponse:ToJson()))
Return .T.
 
//-------------------------------------------------------------------
/*/{Protheus.doc} GET cardFilter
    Devuelve los campos que podrán filtrarse
  
    @author Squad CRM & Facturación
    @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"      , "Tienda"         },;
        {"name"       , "Nombre"         },;
        {"fantasyName", "Nombre fantasía"},;
        {"risk"       , "Riesgo"        };
        }
  
    oResponse["items"]      := oCoreDash:SetPOHeader(aFields)
  
    Self:SetResponse( EncodeUtf8(oResponse:ToJson()))
Return .T.
 
//-------------------------------------------------------------------
/*/{Protheus.doc} RetHeader
    Devuelve los campos del encabezado de los detalles
  
    @author Squad CRM & Facturación
    @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"      , "Tienda"         ,,,,.T.},;
            {"name"       , "Nombre"         ,,,,.T.},;
            {"fantasyName", "Nombre fantasía",,,,.T.},;
            {"risk"       , "Riesgo"        ,,,,.T.};
            }
    ElseIf cTable == "SC5"
        aHeader := {;
            {"num"     , "Número Pedido"        ,,,,.T.},;
            {"type"    , "Tipo Pedido"          ,,,,.T.},;
            {"payment" , "Condición de pago",,,,.T.},;
            {"emission", "Emisión"              ,,,,.T.};
            }
    EndIf
Return aHeader

Pone a disposición una API REST en el Dashboard para visualizar un gráfico de Pizza o Polar. Con el siguiente fuente (Ejemplo) se obtuvo el siguiente Gráfico de ejemplo: 

Para poner a disposición gráficos de pizza/polar, es necesario que la API tenga 3 endpoints:


1. Un GET para devolver el formulario de registro del gráfico:

En el siguiente ejemplo, estas informaciones son devueltas por el endpoint /Ejemplo2/charts/form.

Diferente de los cards, el gráfico tiene un formulario dinámico y es el servicio anteriormente mencionado que debe devolver los datos para el montaje del formulario de registro. En este ejemplo, este nos devolvió el formulario a partir de la línea 'Tipo de gráfico'. Todo lo que viene antes de esta línea, es estándar para todos los gráficos.


El endpoint debe devolver la siguiente estructura json:

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

La propiedad ítems debe devolver la lista con las configuraciones de todos los campos que deben mostrarse en el formulario. Para el montaje de este formulario, se utiliza el componente Dynamic Form del PO-ui, por lo tanto, para entender cada una de las propiedades que se devolverán en este servicio, haga clic aquí.

{
    "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": "Fechas",
            "gridSmColumns": 12,
            "type": "date",
            "property": "datainicio",
            "gridColumns": 6,
            "required": true,
            "label": "De Fch. Emisión"
        },
        {
            "gridSmColumns": 12,
            "type": "date",
            "property": "datafim",
            "gridColumns": 6,
            "required": true,
            "label": "A Fch. Emisión"
        }
    ]
}


2. Un POST para cargar las informaciones del gráfico:

En el siguiente ejemplo, estas informaciones son devueltas por el endpoint /Ejemplo2/charts/retdados.


El endpoint debe devolver la siguiente estructura json:

{
    "items": [
        {
            "chartData": [ Lista de las informaciones que se mostrarán en el gráfico ],
            "chartLabels": [ Lista de los títulos de las informaciones ],
            "charttype": string - Tipo del gráfico,
            "title": string - Título del gráfico
        }
    ]
}

La propiedad ítems debe devolver las informaciones del gráfico como valores que se mostrarán, títulos que representen estos valores, título del gráfico y máscara de valores que se utilizará.

{
    "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": "Factura por Estado/Prov/Reg"
        }
    ]
}


3. Un POST para cargar las informaciones que se mostrarán en los detalles del gráfico:

En el siguiente ejemplo, estas informaciones son devueltas por el endpoint /Ejemplo2/charts/itemsDetails.


El endpoint debe devolver la siguiente estructura json:

{
   "header":[
      {
         "showFilter": boolean,
         "property": string,
         "label":string
      }
   ],
   "items":[
      {
         "property": <Valor devuelto por la query>,
      }
   ],
   "hasNext": boolean
}

La propiedad header se refiere al encabezado de la tabla. Como la tabla utilizada por el dashboard es un componente de la biblioteca PO-UI (po-table), deben informarse las propiedades obligatorias a este componente: property (nombre identificador para la columna) y label (título para la columna). Para más informaciones, haga clic aquí.

La propiedad ítems se refiere a los valores que se mostrarán en las columnas de la tabla, es decir, para cada propiedad informada, la query devolverá un valor. Ejemplo: { "documentType": "N" }. Este debe tener la propiedad "hasNext" para informar si existe una próxima página (true) o no (false).

{
    "header": [
        {
            "showFilter": true,
            "type": "link",
            "property": "document",
            "label": "Documento",
            "action": "Enlace"
        },
        {
            "showFilter": true,
            "property": "series",
            "label": "Serie"
        },
        {
            "showFilter": true,
            "property": "state",
            "label": "ESTADO/PROV/REG"
        },
        {
            "showFilter": true,
            "property": "documentType",
            "label": "Tipo"
        },
        {
            "showFilter": true,
            "property": "dateOfIssue",
            "label": "Emisión"
        }
    ],
    "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
}           
            

Haga clic aquí para download del fuente de ejemplo.

#INCLUDE "TOTVS.CH"
#INCLUDE "RESTFUL.CH"
 
//------------------------------------------------------------------------
/*/{Protheus.doc} Exemplo2
    Ejemplo de API de integración de Gráficos de Pizza y/o Polar
 
    @author     Squad CRM & Facturación
    @since      26/03/2020
    @version    12.1.27
/*/
//------------------------------------------------------------------------
WSRESTFUL Ejemplo2 DESCRIPTION "Ejemplo de API - Gráfico Pizza y 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 Registro del gráfico" ;
        WSSYNTAX "/charts/form/" ;
        PATH "/charts/form";
        PRODUCES APPLICATION_JSON
 
    WSMETHOD POST retdados ;
        DESCRIPTION "Devuelve las informaciones del gráfico" ;
        WSSYNTAX "/charts/retdados/{JsonFilter}" ;
        PATH "/charts/retdados";
        PRODUCES APPLICATION_JSON
 
    WSMETHOD POST itemsDetails ;
        DESCRIPTION "Activa el detalle del gráfico" ;
        WSSYNTAX "/charts/itemsDetails/{JsonFilter}" ;
        PATH "/charts/itemsDetails";
        PRODUCES APPLICATION_JSON
 
ENDWSRESTFUL
 
//-------------------------------------------------------------------
/*/{Protheus.doc} GET form
    Devuelve los campos que se mostraron en el Registro del grafico.
    Debe seguir el formato del Dynamic Form del PO-UI.
    https://po-ui.io/tools/dynamic-form
     
    @author Squad CRM & Facturación
    @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("Fechas"              , "datainicio"      , 6   , "De Fch. Emisión"      , .T., "date")
    oCoreDash:SetPOForm(""                   , "datafim"         , 6   , "A Fch. Emisión"     , .T., "date")  
 
    oResponse  := oCoreDash:GetPOForm()
 
    Self:SetResponse( EncodeUtf8(oResponse:ToJson()))
 
Return .T.
 
//-------------------------------------------------------------------
/*/{Protheus.doc} POST retdados
    Devuelve un objeto JSON con las informaciones y valores del gráfico
 
    @author Squad CRM & Facturación
    @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
    Devuelve los ítems utilizados en el Drilldown
 
    @author Squad CRM & Facturación
    @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      := "Error en la eequisición"
    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 del Drilldown
            aHeader := {;
                {"document"     , "Documento" ,"enlace"   },;
                {"series"       , "Serie"               },;
                {"state"        , ESTADO/PROV/REG"                  },;
                {"documentType" , "Tipo"                },;
                {"dateOfIssue"  , "Emisión"             };
                }
 
            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 del Drilldown
 
            aHeader := {;
                {"D2_ITEM"  , "Ítem"                            },;
                {"D2_COD"   , "Cód. Producto", "enlace"            },;
                {"B1_DESC"  , "Desc. Producto "                  },;
                {"D2_PRCVEN", "Val.Unitario", "currency","BRL"  },;
                {"D2_QUANT" , "Cantidad","number",'1.2-5'     },;
                {"D2_TOTAL" , "Val. Total", "currency","BRL"    },;
                {"D2_LOCAL" , "Almacén"                         };
                }
 
            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 del Drilldown
            aHeader := {;
                {"B1_COD"   , "Cód. Producto"                      },;
                {"B1_DESC"  , "Desc. Producto "                    },;
                {"B1_PRV1"  , "Precio de venta", "currency","BRL"  },;
                {"B1_TE"    , "TES Entrada Est"                   },;
                {"B1_TS"    , "TES Salida Est"                     };
                }
 
            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 el Drilldown del gráfico nivel 2
        aHeader := {;
            {"document"     , "Documento"   },;
            {"series"       , "Serie"               },;
            {"state"        , "ESTADO/PROV/REG"                  },;
            {"documentType" , "Tipo"                },;
            {"dateOfIssue"  , "Emisión"             };
            }
 
        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
    Devuelve los datos que podrán mostrarse en el grafico
 
    @author Squad CRM & Facturación
    @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*/,,"Factura por Estado/Prov/Reg"))
    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","Cantidad de facturas 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, 'Facturas', 'bar', aCores[8][3] ) //Color utilizado: OrangeLht
        aAdd(aDataFim, oCoreDash:SetChart(aCab,,/*lCurrency*/,"bar","TOP 10 Clientes por tipo de factura"))
 
    Endif
 
    oResponse["items"] := aDataFim
 
Return Nil
 
 
//-------------------------------------------------------------------
/*/{Protheus.doc} QuerySF2
    Monta la query responsable por traer los registros de la factura
 
    @param cSelect, Carácter, Campos que se devolverán en el SELECT
    @param cFilter, Carácter, Filtro complementario utilizado en la cláusula WHERE
    @author Squad CRM & Facturación
    @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 la query responsable por traer los registros de la factura
 
    @param cSelect, Carácter, Campos que se devolverán en el SELECT
    @param cFilter, Carácter, Filtro complementario utilizado en la cláusula WHERE
    @author Squad CRM & Facturación
    @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 la query responsable por traer el documento del Reg. Producto
 
    @param cSelect, Carácter, Campos que se devolverán en el SELECT
    @param cFilter, Carácter, Filtro complementario utilizado en la cláusula WHERE
    @author Squad CRM & Facturación
    @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
Devuelve ESTADO/PROV/REG
 
@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
Devuelve los tipos de factura
 
@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.Precio/Cantidad')
    aAdd(aTipoNF, 'I=Compl.ICMS')
    aAdd(aTipoNF, 'P=Compl.IPI')
    aAdd(aTipoNF, 'D=Dev.Compras')
    aAdd(aTipoNF, 'B=Utiliza Proveedor')

Return aTipoNF

Servicios gráficos de Barra/Línea

Pone a disposición una API REST en el Dashboard para visualizar un gráfico de Barra Línea. Con el siguiente fuente se obtuvo el siguiente Gráfico de ejemplo: 

Para poner a disposición gráficos en barra/línea, es necesario que la API tenga 3 endpoints:


1. Un GET para devolver el formulario de registro del gráfico:

En el siguiente ejemplo, estas informaciones son devueltas por el endpoint /Ejemplo/charts/form.

Diferente de los cards, el gráfico tiene un formulario dinámico y es el servicio que debe devolver el formulario de registro este. En este ejemplo, este nos devolvió el formulario a partir de la línea 'Tipo de gráfico'. Todo lo que viene antes de esta línea, es estándar para todos los gráficos.


El endpoint debe devolver la siguiente estructura json:

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

La propiedad ítems debe devolver la lista con las configuraciones de todos los campos que deben mostrarse en el formulario. Para el montaje de este formulario, se utiliza el componente Dynamic Form del PO-ui, por lo tanto, para entender cada una de las propiedades que se devolverán en este servicio, haga clic aquí.

{
    "items": [
        {
            "divider": "Tipo de gráfico",
            "gridSmColumns": 12,
            "options": [
                {
                    "value": "line",
                    "label": "Línea"
                },
                {
                    "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": "Fecha inicial"
        },
        {
            "gridSmColumns": 12,
            "type": "date",
            "property": "dateFim",
            "gridColumns": 6,
            "required": true,
            "label": "Fecha final"
        }
    ]
}


2. Un POST para cargar las informaciones del gráfico:

En el siguiente ejemplo, estas informaciones son devueltas por el endpoint /Ejemplo3/charts/retdados.


El endpoint debe devolver la siguiente estructura json:

{
    "items": [
        {
            "chartData": [
                {
                    "data": [ Valores que se mostrarán ],
                    "fill": false,
                    "drillDown": true,
                    "backgroundColor": "rgba(255,162, 54, 1)" - Color de la línea,
                    "hoverBackgroundColor": "rgba(255,162, 54, 1)" - Color de la línea al pasar el mouse,
                    "label": string - Título que representa el conjunto de información y que aparecerá en la leyenda,
                    "lineTension": number - Tensión de la curva de la línea. Si fuera 0, la línea será recta
                }
            ],
            "chartLabels": [ Títulos correspondientes a los valores que se mostrarán ],
            "charttype": string - Tipo de gráfico,
            "title": string - Título del gráfico,
            "chartMask": string,
            "currencyMask": [ Máscaras utilizadas para mostrar valores ]
        }
    ]
}

La propiedad ítems debe devolver las informaciones del gráfico como valores que se mostrarán, títulos que representen estos valores, título del gráfico y máscara de valores que se utilizará.

El gráfico utiliza la biblioteca chart.js. Para más información sobre sus propiedades, haga clic aquí.

{
    "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": "Promedio",
                    "lineTension": 0
                }
            ],
            "chartLabels": [
                "Enero",
                "Febrero",
                "Marzo"
            ],
            "charttype": "",
            "title": null,
            "chartMask": "currency",
            "currencyMask": [
                {
                    "maskFrac": "R$",
                    "maxiFrac": 10,
                    "miniFrac": 2
                }
            ]
        }
    ]
}


3. Un POST para cargar las informaciones que se mostrarán en los detalles del gráfico:

En el siguiente ejemplo, estas informaciones son devueltas por el endpoint /Ejemplo3/charts/itemsDetails.


El endpoint debe devolver la siguiente estructura json:

{
   "header":[
      {
         "showFilter": boolean,
         "property": string,
         "label":string
      }
   ],
   "items":[
      {
         "property": <Valor devuelto por la query>,
      }
   ],
   "hasNext": boolean
}

La propiedad header se refiere al encabezado de la tabla. Como la tabla utilizada por el dashboard es un componente de la biblioteca PO-UI (po-table), deben informarse las propiedades obligatorias a este componente: property (nombre identificador para la columna) y label (título para la columna). Para más informaciones, haga clic aquí.

La propiedad ítems se refiere a los valores que se mostrarán en las columnas de la tabla, es decir, para cada propiedad informada, la query devolverá un valor. Ejemplo: { "totalValor":  }. Este debe tener la propiedad "hasNext" para informar si existe una próxima página (true) o no (false).

{
    "header": [
        {
            "showFilter": true,
            "type": "link",
            "property": "codigo",
            "label": "Código",
            "action": "Enlace"
        },
        {
            "showFilter": true,
            "property": "nome",
            "label": "Nombre vendedor"
        },
        {
            "showFilter": false,
            "format": "1.2-5",
            "type": "number",
            "property": "totalItens",
            "label": "Total de ítems"
        },
        {
            "showFilter": false,
            "format": "BRL",
            "type": "currency",
            "property": "totalValor",
            "label": "Valor total"
        }
    ],
    "items": [
        {
            "totalValor": 2000,
            "totalItens": 1,
            "nome": "10% COMIS 100%EMISIÓN",
            "codigo": "FIN058"
        },
        {
            "totalValor": 2000,
            "totalItens": 1,
            "nome": "10% COMISIÓN 100% BAJA   DESCUENTA IMPUESTOS",
            "codigo": "FIN056"
        },
        {
            "totalValor": 2000,
            "totalItens": 1,
            "nome": "10% COMISIÓN 100% BAJA DESCUENTA IMPUESTOS",
            "codigo": "FIN060"
        },
        {
            "totalValor": 2000,
            "totalItens": 1,
            "nome": "10% COMISIÓN 100% EMISIÓN DESCUENTA IMPUESTOS",
            "codigo": "FIN055"
        },
        {
            "totalValor": 2000,
            "totalItens": 1,
            "nome": "10% COMISIÓN 100% EMISIÓN DESCUENTA IMPUESTOS",
            "codigo": "FIN059"
        },
        {
            "totalValor": 5000,
            "totalItens": 4,
            "nome": "100% BAJA 10%COMISIÓN",
            "codigo": "FVEN10"
        },
        {
            "totalValor": 1000,
            "totalItens": 1,
            "nome": "100%baja 0%comisión",
            "codigo": "FIN048"
        },
        {
            "totalValor": 2000,
            "totalItens": 2,
            "nome": "100%emisión 0%comisión",
            "codigo": "FIN047"
        },
        {
            "totalValor": 200000,
            "totalItens": 2,
            "nome": "5% COMISIÓN 100% BAJA",
            "codigo": "FIN600"
        },
        {
            "totalValor": 1000,
            "totalItens": 1,
            "nome": "50 50 - 10%",
            "codigo": "FIN073"
        }
    ],
    "hasNext": true
}  
            

Haga clic aquí para download del fuente de ejemplo.

#INCLUDE "TOTVS.CH"
#INCLUDE "RESTFUL.CH"
 
//------------------------------------------------------------------------
/*/{Protheus.doc} Exemplo3
    Ejemplo de API de integración de Gráficos de Barra y Línea
 
    @author     Squad CRM & Facturación
    @since      28/07/2020
    @version    12.1.27
/*/
//------------------------------------------------------------------------
WSRESTFUL Ejemplo3 DESCRIPTION "Ejemplo de API - Gráfico Barra y Línea"
    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 Registro del gráfico" ;
        WSSYNTAX "/charts/form/" ;
        PATH "/charts/form";
        PRODUCES APPLICATION_JSON
 
    WSMETHOD POST retDados ;
        DESCRIPTION "Debe devolver las informaciones mostradas en el gráfico." ;
        WSSYNTAX "/charts/retDados/{JsonFilter}" ;
        PATH "/charts/retDados";
        PRODUCES APPLICATION_JSON
 
    WSMETHOD POST itemsDetails ;
        DESCRIPTION "Activa el detalle del gráfico" ;
        WSSYNTAX "/charts/itemsDetails/{JsonFilter}" ;
        PATH "/charts/itemsDetails";
        PRODUCES APPLICATION_JSON
 
ENDWSRESTFUL
 
//-------------------------------------------------------------------
/*/{Protheus.doc} GET form
  Devuelve los campos que se mostrarán en el formulario.
  El estándar del campo debe seguir o Dynamic Form del Portinari.
 
  @author Squad CRM & Facturación
  @since 27/03/2020
  @version Protheus 12.1.27
/*/
//-------------------------------------------------------------------
WSMETHOD GET form WSSERVICE Ejemplo3
 
    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","Línea"}, {"bar","Barra"}}))
    oCoreDash:SetPOForm("Filtros"        , "dateIni"         , 6, "Fecha inicial"           , .T., 'date'   , , .T.)
    oCoreDash:SetPOForm(""               , "dateFim"         , 6, "Fecha final"             , .T., 'date'   , , .T.)
    oCoreDash:SetPOForm(""               , "person"          , 6, "Persona"                 , .F., 'string' , oCoreDash:SetPOCombo({{"F","Física"}  , {"J","Jurídica"}}), .T.)
    oCoreDash:SetPOForm(""               , "blocked"         , 6, "¿Bloqueado?"             , .F., 'string' , oCoreDash:SetPOCombo({{"1","Sí"}     , {"2","No"}})     , .F.)
 
    oResponse  := oCoreDash:GetPOForm()
 
    Self:SetResponse( EncodeUtf8(oResponse:ToJson()))
 
Return .T.
 
//-------------------------------------------------------------------
/*/{Protheus.doc} POST retDados
  Devuelve los datos del gráfico
 
  @author Squad CRM & Facturación
  @since 27/03/2020
  @version Protheus 12.1.27
/*/
//-------------------------------------------------------------------
WSMETHOD POST retDados WSRECEIVE JsonFilter WSSERVICE Ejemplo3
 
    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
  Devuelve el valor de las Metas y el Valor vendido de acuerdo con parámetros  
  informados
 
  @author Squad CRM & Facturación
  @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' }



        //######### Obtener los filtros del registro o del usuario y aplicar en la query #########
       
        // Filtro por tipo da persona - Con Multiselección
        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 de persona - con una única selección
        If oJson:HasProperty("blocked") .And. ValType(oJson["blocked"]) == "C"
          cFiltros += "AND SA1.A1_MSBLQL = '" + oJson["blocked"] + "'"
        EndIf

        //######### Final de la obtención de los filtros del registro o del usuario y aplicar en la 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, 'Riesgo A', , aCores[8][3] ) //Color utilizado: OrangeLht
        oCoreDash:SetChartInfo( aData2, 'Riesgo B', , aCores[1][3] ) //Color utilizado: GreenDk
        oCoreDash:SetChartInfo( aData3, 'Riesgo C', , aCores[6][3] ) //Color utilizado: YellowDk
        oCoreDash:SetChartInfo( aData4, 'Riesgo D', , aCores[15][3] ) //Color utilizado: 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, 'Promedio', "line", aCores[9][3] ,,.F.) //Color utilizado: BlueDk    
 
        aDataFim := {}
        aAdd(aDataFim, oCoreDash:SetChart(aCab,,.F., ,"Cantidad de clientes por riesgo en cada Estado/Prov/Reg"))
    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., ,"Mayores ventas - " + 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", "Mayores clientes - " + oJson["level"][2]["labelDataSet"] + " - " + oJson["level"][1]["label"]))
    EndIf
    oResponse["items"] := aDataFim
 
Return
 
//-------------------------------------------------------------------
/*/{Protheus.doc} POST itemsDetails
  Método para devolver los datos del panel
 
  @author Squad CRM & Facturación
  @since 27/03/2020
  @version Protheus 12.1.27
/*/
//-------------------------------------------------------------------
WSMETHOD POST itemsDetails WSRECEIVE JsonFilter, drillDownFilter WSRESTFUL Ejemplo3
 
  Local aHeader     := {}
  Local aItems      := {}
  Local aRet        := {}
  Local cBody       := DecodeUtf8(Self:GetContent())
  Local cError        := "Error en la requisición"
  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 el nivel del gráfico
  If oJsonFilter:GetJsonText("level") == "null" .Or. Len(oJsonFilter["level"]) == 0
    //Verifico el nivel del Drilldown
    If Len(oJsonDD) == 0
      aHeader := {;
          {"codigo"     , "Código"        ,"enlace"               },;
          {"nombre"         , "Nombre vendedor"                       },;
          {"totalItens" , "Total de ítems","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
      //Si quisiera tomar el nombre del nivel seleccionado : oJsonFilter["level"][1]["labelDataSet"]
      // Si fuese gráfico del tipo pizza: oJsonFilter["level"][1]["label"]
      aHeader := {;
          {"codigoPed"  , "Código del pedido"    },;
          {"codigoCli"  , "Código del cliente"   },;
          {"nome"         , "Nombre"                },;
          {"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]["código"] + "'")
    EndIf
  ElseIf Len(oJsonFilter["level"]) == 1
    aHeader := {;
          {"codigoPed"  , "Código del pedido"    },;
          {"codigoCli"  , "Código del cliente"   },;
          {"nome"         , "Nombre"                },;
          {"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"       , "Nombre vendedor" },;
        {"totalItens" , "Total de ítems","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 y el Total de los pedidos de venta
 
  @author Squad CRM & Facturación
  @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 la Query del Pedido de ventas realizando un filtro específo.
 
  @author Squad CRM & Facturación
  @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'   "  // Límite incluido para evitar lentitud en la devolución de la query en bases con una cantidad muy grande de pedidos de venta
 
  cGroup := " C5_NUM, C5_CLIENTE, SA1.A1_NOME "
 
Return {cQuery, cWhere, cGroup}
 
//-------------------------------------------------------------------
/*/{Protheus.doc} RetRisco
    Devuelve el total de clientes de acuerdo con el riesgo informado en el
    filtro
   
    @param cFiltro, Carácter, Filtro que se incluirá en la query
    @author Squad CRM & Facturación
    @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 la query responsable por traer los clientes de acuerdo con el
    riesgo informado en el filtro
   
    @param cCampos,  Carácter, Campos que se devolverán en el SELECT
    @param cFiltro,  Carácter, Filtro que se incluirá en la query
    @param cGroupBy, Carácter, Expresión group by que se incluirá en la query
    @author Squad CRM & Facturación
    @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}

Pone a disposición una API REST en el Dashboard para visualizar un gráfico de Gauge. Con el siguiente fuente se obtuvo el siguiente Gráfico de ejemplo: 

Para poner a disposición gráficos en gauge, es necesario que la API tenga 3 endpoints:


1. Un GET para devolver el formulario de registro del gráfico:

En el siguiente ejemplo, estas informaciones son devueltas por el endpoint /Ejemplo4/charts/form.


Diferente de los cards, el gráfico tiene un formulario dinámico y es el servicio que debe devolver el formulario de registro este. En este ejemplo, este nos devolvió el formulario a partir de la línea 'Tipo de gráfico'. Todo lo que viene antes de esta línea, es estándar para todos los gráficos.

El endpoint debe devolver la siguiente estructura json:

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

La propiedad ítems debe devolver la lista con las configuraciones de todos los campos que deben mostrarse en el formulario. Para el montaje de este formulario, se utiliza el componente Dynamic Form del PO-ui, por lo tanto, para entender cada una de las propiedades que se devolverán en este servicio, haga clic aquí.

{
    "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": "De Fecha",
            "required": false,
            "type": "date",
            "gridSmColumns": 12
        },
        {
            "property": "datafim",
            "gridColumns": 6,
            "label": "A Fecha",
            "required": false,
            "type": "date",
            "gridSmColumns": 12
        }
    ]
}


2. Un POST para activar las informaciones del gráfico:

En el siguiente ejemplo, estas informaciones son devueltas por el endpoint /Ejemplo4/charts/retdados.


El endpoint debe devolver la siguiente estructura json:

{
    "items": [
        {
            "chartData": [
                {
                    <valor devuelto por la query>: number
                }
            ],
            "chartLabels": [ Título correspondiente al valor que se mostrará ],
            "charttype": string - Tipo de gráfico,
            "title": string - Título del gráfico,
            "chartMask": string
        }
    ]
}

La propiedad ítems debe devolver las informaciones del gráfico como el valor que se mostrará, título que representará este valor, título del gráfico y máscara de valores que se utilizará.

El gráfico utiliza el componente gauge de la biblioteca PO-ui. Para más información sobre sus propiedades, haga clic aquí.

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


3. Un POST para activar las informaciones que se mostrarán en los detalles del gráfico:

En el siguiente ejemplo, estas informaciones son devueltas por el endpoint /Ejemplo4/charts/itemsDetails.


El endpoint debe devolver la siguiente estructura json:

{
   "header":[
      {
         "showFilter": boolean,
         "property": string,
         "label":string
      }
   ],
   "items":[
      {
         "property": <Valor devuelto por la query>,
      }
   ],
   "hasNext": boolean
}

La propiedad header se refiere al encabezado de la tabla. Como la tabla utilizada por el dashboard es un componente de la biblioteca PO-UI (po-table), deben informarse las propiedades obligatorias a este componente: property (nombre identificador para la columna) y label (título para la columna). Para más informaciones, haga clic aquí.

La propiedad ítems se refiere a los valores que se mostrarán en las columnas de la tabla, es decir, para cada propiedad informada, la query devolverá un valor. Ejemplo: { "totalValor":  }. Este debe tener la propiedad "hasNext" para informar si existe una próxima página (true) o no (false).

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

Haga clic aquí para download del fuente de ejemplo.

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

//------------------------------------------------------------------------
/*/{Protheus.doc} Ejemplo4
  API - Ejemplo 4 - Gráfico de Gauge

  @author	Squad CRM/Facturación
  @since	11/05/2022
  @version  12.1.33
  @return 	Json
/*/
//------------------------------------------------------------------------
WSRESTFUL Ejemplo4 DESCRIPTION "Ejemplo 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 "Activa los campos que se mostrarán en el formulario" ;
    WSSYNTAX "/charts/form/" ;
    PATH "/charts/form";
    PRODUCES APPLICATION_JSON

  WSMETHOD POST retdados ;
    DESCRIPTION "Activa los ítems" ; 
    WSSYNTAX "/charts/retdados/{JsonFilter}" ;
    PATH "/charts/retdados";
    PRODUCES APPLICATION_JSON

  WSMETHOD POST itemsDetails ;
    DESCRIPTION "Activa los ítems utilizados para montaje de los detalles" ;
    WSSYNTAX "/charts/itemsDetails/{JsonFilter}" ;
    PATH "/charts/itemsDetails";
    PRODUCES APPLICATION_JSON

ENDWSRESTFUL

//-------------------------------------------------------------------
/*/{Protheus.doc} GET form
  Devuelve los campos que se mostrarán en el formulario.
  El estándar del campo debe seguir el Dynamic Form del Portinari.
  
  @author Squad CRM & Facturamción
  @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 , "De Fecha" ; 
  , .F., "date"   )
  
  oCoreDash:SetPOForm(""      , "datafim"       , 6 , "A Fecha" ;
  , .F., "date"   )

  oResponse  := oCoreDash:GetPOForm()

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

Return .T.

//-------------------------------------------------------------------
/*/{Protheus.doc} POST retDados
  Devuelve los datos del gráfico
  
  @author Squad CRM & Facturación
  @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 devolver los datos detallados por ítems del gráfico
  
  @author Squad CRM & Facturación
  @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		  := "Error en la requisición"
  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" , "Tienda 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
  Devuelve el valor de la cantidad de pedidos de acuerdo con parámetros
  informados
  
  @author Squad CRM & Facturación
  @since 16/05/2022
  @version Protheus 12.1.33
/*/
//-------------------------------------------------------------------
Static Function retDados(oResponse, oCoreDash, oJson, dDataIni, dDataFim)
  Local aData    := {}
  Local aDataFim := {}
  Local aCab     := {}

  aCab := {"Cantidade de pedidos"}

  oData   := JsonObject():New()

  aData   := { 45 /*Complete aquí con el valor devuelto por su query. Para el ejemplo está fijo 45*/ }

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

  oResponse["items"] := aDataFim

Return Nil

//-------------------------------------------------------------------
/*/{Protheus.doc} QuerySC5
    Monta la query responsable por traer los ítems detallados
    utilizados en el gráfico
   
    @param cSelect,  Caractere, Campos que se devolverán en el SELECT
    @param cFilter,  Carácter, Filtro que se incluirá en la query
    @author Squad CRM & Facturación
    @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}

ATENCIÓN: Regla de paginación obligatoria

Para los servicios cuya devolución solicita la propiedad "hasNext", quiere decir que estos tienen paginación. La paginación con la utilización de la clase CoreDash es obligatoria y funciona por medio de los parámetros page (indica la página que se devolverá) y pageSize (indica cuántos registros de la página deben devolverse). Sus valores default son page = 1 e pageSize = 10.

Ejemplo de utilización: /Ejemplo1/cards/itemsDetails?page=2&pageSize=10


03. MÉTODOS

Métodos de la clase

Sintaxis:

CoreDash():New()

Descripción:

Método construtor de la clase.

Ejemplo de utilización
Local oCoreDash := CoreDash():New() 

Sintaxis:

CoreDash():SetFields(aCampos)

Descripción:

Método que define los campos que se devolverán en el JSON del servicio.

Parámetros:

NombreTipoDescripciónDefaultObligatorioReferencia
aCamposArrayArray que contiene el De / A de los campos que se mostrarán en el servicio
X
Ejemplo de utilización
Local oCoreDash := CoreDash():New() 
Local aCampos 	 := {} 
 
Aadd(aCampos, {"code", "A1_CODIGO"}) 
Aadd(aCampos, {"name", "A1_NOME"}) 
oCoreDash:SetFields(aCampos) 

Sintaxis:

CoreDash():SetQuery(cQuery)

Descripción:

Método que define la query que se utilizará en el servicio.

Parámetros:

NombreTipoDescripciónDefaultObligatorioReferencia
cQueryCarácterRecibe la query que se ejecutará. 
X
Ejemplo de utilización
Local oCoreDash := CoreDash():New() 
Local cQuery 	 := "" 

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

Sintaxis:

CoreDash():SetWhere(cWhere)

Descripción:

Método que define la cláusula where que será en el método SetQuery().

Parámetros:

NombreTipoDescripciónDefaultObligatorioReferencia
cWhereCaractereWhere que se utilizará en la query enviada al método SetQuery()  


Ejemplo de utilización
Local oCoreDash := CoreDash():New() 
Local cQuery 	 := " SELECT A1_COD, A1_NOME FROM "+ RetSqlName("SA1") + " SA1 "
Local cWhere 	 := "" 

oCoreDash:SetQuery(cQuery)

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

Sintaxis:

CoreDash():SetIndexKey(cIndexFather)

Descripción:

Método que atribuye el orden del Alias principal.

Parámetros:

Nombre

Tipo

Descripción

Estándar

Obligatorio

Referencia

cIndexFather

Carácter

Orden utilizado en el alias




Ejemplo de utilización
Local oCoreDash := CoreDash():New() 

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

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

Sintaxis:

CoreDash():SetGroupBy(cGroup)

Descripción:

Método responsable por definir un agrupador en la query utilizada en el servicio.

Parámetros:

Nombre

Tipo

Descripción

Estándar

Obligatorio

Referencia

cGroup

Carácter

Campos que deben componer el agrupador


X


Ejemplo de utilización
Local oCoreDash := CoreDash():New() 
Local cQuery	 := " SELECT tbl.CAMPO1, tbl.CAMPO2, COUNT(1) COUNT FROM TABLE tbl "
Local cWhere	 := " WHERE FILIAL = 'valor' AND D_E_L_E_T_ = ' ' "

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

Sintaxis:

CoreDash():SetPage(nPage)

Descripción:

Método que atribuye el número de la página donde el usuario va a navegar.

Parámetros:

Nombre

Tipo

Descripción

Estándar

Obligatorio

Referencia

nPage

Numérico

Número de la página que se mostrará al usuario

1



Ejemplo de utilización
Local oCoreDash := CoreDash():New()
Local nPage 	 := 8 

oCoreDash:SetPage(nPage)

Sintaxis:

CoreDash():SetPageSize(nPageSize)

Descripción:

Método que atribuye la cantidad máxima de registros que se mostrarán por página.

Parámetros:

Nombre

Tipo

Descripción

Estándar

Obligatorio

Referencia

nPageSize

Numérico

Cantidad máxima de registros mostrados por página al usuario.

10



Ejemplo de utilización
Local oCoreDash := CoreDash():New()
Local nPageSize	 := 20

oCoreDash:SetPageSize(nPageSize)

Sintaxis:

CoreDash():DefFields(lConvProt, cField)

Descripción:

Método que efectúa la conversión entre campos del Objeto y Protheus

Parámetros:

Nombre

Tipo

Descripción

Estándar

Obligatorio

Referencia

lConvProt

Lógico

Define si debe convertir los campos al estándar Protheus

.T.



cField

Carácter

Campo que se convertirá




Ejemplo de utilización
Local oCoreDash := CoreDash():New()

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

Sintaxis:

CoreDash():GetDataType(lConvProt, cField)

Descripción:

Devuelve el tipo del dato de un determinado campo.

Parámetros:

Nombre

Tipo

Descripción

Estándar

Obligatorio

Referencia

lConvProt

Lógico

Define si debe convertir los campos al estándar Protheus

.T.



cField

Caracteres

Campo que se convertirá




Ejemplo de utilización
Local oCoreDash := CoreDash():New()
Local dData

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

Sintaxis:

CoreDash():SetFieldsFilt(cFields) 

Descripción:

Método que define qué campos se devolverán por el servicio.

Parámetros:

Nombre

Tipo

Descripción

Estándar

Obligatorio

Referencia

cFields

Carácter

Campos que se devolverán en el JSON.


X


Ejemplo de utilización
Local oCoreDash := CoreDash():New()
Local cFields 	 := "order, totValue, product"

oCoreDash:SetFieldsFilt(cFields) 

Sintaxis:

CoreDash():ToObjectJson()

Descripción:

Método que devuelve el JSON serializado.

Ejemplo de utilización
Local oCoreDash := CoreDash():New()
Local lRet 		 := .T. 
Local cError := "Error en la requisición"
 
If lRet 
	Self:SetResponse( oCoreDash:ToObjectJson())
Else 
	cError := oCoreDash:GetJsonError() 
	SetRestFault( 500,  EncodeUtf8(cError) ) 
EndIf 

Sintaxis:

CoreDash():ToSingleObject()

Descripción:

Método que retorna un JSON serializado a solamente un objeto.

Se utiliza en requisiciones del tipo GET que devuelven informaciones de solamente un registro.

Ejemplo de utilización
Local oCoreDash := CoreDash():New()
Local cError     := "Error en la requisición"
Local lRet 		 := .T. 
 
If lRet 
	Self:SetResponse(oCoreDash:ToSingleObject()) 
Else 
	cError := oCoreDash:GetJsonError() 
	SetRestFault( 500,  EncodeUtf8(cError) ) 
EndIf 

Sintaxis:

CoreDash():GetJsonObject()

Descripción:

Método que devuelve el objeto JSON de la clase

Ejemplo de utilización
Local oCoreDash := CoreDash():New()
Local oJson

oJson:= oCoreDash:GetJsonObject()

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

Sintaxis:

CoreDash():SetApiQstring(aQueryString)

Descripción:

Método que define los campos (Devueltos por el JSON), page (página que se mostrará) y pagesize (Cantidad máxima de registros por página) y filtros.

Parámetros:

Nombre

Tipo

Descripción

Estándar

Obligatorio

Referencia

aQueryString

Array

Recibe el filtro que se utilizará al devolver al JSON




Ejemplo de utilización
Local oCoreDash 	:= CoreDash():New()
Local aQueryString 	:= {} 

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

oCoreDash:SetApiQString(aQueryString) 

Sintaxis:

CoreDash():SetApiFilter(aFilter)

Descripción:

Método que atribuye un filtro de búsqueda.

Parámetros:

Nombre

Tipo

Descripción

Estándar

Obligatorio

Referencia

aFilter

Array

Array con expresiones de filtro que se utilizarán


X


Ejemplo de utilización
Local oCoreDash 	:= CoreDash():New()
Local aFilter		:= {} 

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

oCoreDash:SetApiFilter(aFilter)

Sintaxis:

CoreDash():GetApiFilter()

Descripción:

Método que devuelve el filtro de búsqueda.

Ejemplo de utilización
Local oCoreDash 	:= CoreDash():New()

oCoreDash:GetApiFilter()

Sintaxis:

CoreDash():BuildJson()

Descripción:

Método responsable por construir el objeto JSON.

Ejemplo de utilización
Local oCoreDash  := CoreDash():New() 
 
Self:SetContentType("application/json") 
 
oCoreDash:SetQuery(cQuery) 
oCoreDash:SetWhere(cWhere) 
oCoreDash:SetFields(aCampos) 
oCoreDash:SetApiQstring(aQueryString) 
oCoreDash:BuildJson() 

Sintaxis:

CoreDash():SetJson(lHasNext, aItems)

Descripción:

Método responsable por atribuir un objeto JSON, de acuerdo con el contrato establecido por TOTVS, conteniendo el [items] y el [hasNext].

Parámetros:

Nombre

Tipo

Descripción

Estándar

Obligatorio

Referencia

lHasNext

Lógico

Indica si el objeto tiene próxima página.

.T.



aItems

Array

Array con los valores del objeto.




Ejemplo de utilización
Local aItems 		:= {} 
Local lHasNext 		:= .T. 
Local oCoreDash  	:= CoreDash():New() 
Local oItem 		:= JsonObject():New()
 
If (cTemp)->(Eof()) 
	lHasnext := .F. 
EndIf 
 
aAdd(aItems, oItem) 
oCoreDash:SetJson(lHasNext, aItems) 

Sintaxis:

CoreDash():SetTable(cAlias)

Descripción:

Método que recibe el alias que será responsable por la generación del JSON.

Parámetros:

Nombre

Tipo

Descripción

Estándar

Obligatorio

Referencia

cAlias

Carácter

Alias recibido para la generación del JSON.


X


Ejemplo de utilización
Local oCoreDash := CoreDash():New() 
Local cAlias 	 := GetNextAlias() 
 
oCoreDash:SetTable(cAlias) 

Sintaxis:

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

Descripción:

Método que efectúa la inclusión o modificación de registros.

Parámetros:

Nombre

Tipo

Descripción

Estándar

Obligatorio

Referencia

cAlias

Carácter

Alias recibido para la generación del JSON.


X


cIndex

Carácter

Índice utilizado en la búsqueda.




cBody

Carácter

JSON recibido en el Body del mensaje.


X


Ejemplo de utilización
Local oCoreDash := CoreDash():New() 

If oCoreDash:SetUpsertData(cAlias, Nil, cBody)
	Self:SetResponse( EncodeUtf8("Registro incluido con éxito"))
Else
	SetRestFault( 500,  EncodeUtf8("Falla al convertir el archivo.") )
Endif 

Sintaxis:

CoreDash():Destroy()

Descripción:

Método responsable por destruir el objeto.

Ejemplo de utilización
Local oCoreDash := CoreDash():New() 

If oCoreDash:SetUpsertData(cAlias, Nil, cBody)
	Self:SetResponse( EncodeUtf8("Registro incluido con éxito"))
Else
	SetRestFault( 500,  EncodeUtf8("Falla al convertir el archivo.") )
Endif 

oCoreDash:Destroy()

ATENCIÓN: El método estará a disposición en la expedición continua de Facturación.

Para se utilizar este método debe actualizar los fuentes con el paquete de expedición continua de FACTURACIÓN del día 06/05/2022.

Sintaxis:

CoreDash():GetJsonError()

Descripción:

Devuelve string con el mensaje de error del JSON.

Ejemplo de utilización
Local oCoreDash := CoreDash():New() 

If oCoreDash:SetUpsertData(cAlias, Nil, cBody)
	Self:SetResponse( EncodeUtf8("Registro incluido con éxito"))
Else
	SetRestFault( 500,  oCoreDash:GetJsonError() )
Endif 

Sintaxis:

CoreDash():SetPOHeader(aFields)

Descripción:

Método responsable por devolver un Array de acuerdo con lo esperado e la propiedad p-columns del componente Table de la biblioteca de componentes PO-UI

Parámetros:

Nombre

Tipo

Descripción

Estándar

Obligatorio

Referencia

aFields

Array

Array de hasta seis dimensiones con los datos:

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

aFields[n, 2] = Label - Título de la columna mostrada en la tabla (String)

aFields[n, 3] = Tipo del dato - Tipos aceptados actualmente: number, string, currency y link (String)

aFields[n, 4] = Formato/máscara del dato (String)

aFields[n, 5] = Indica si el campo podrá utilizarse en el filtro de los detalles (String 'false' o 'true')

aFields[n, 6] = Indica si el campo será visible en la tabla (String 'false' o 'true')


X


Ejemplo de utilización
Local aFields 	 := {}
Local aItems     := {}
Local oResponse	 :=	JsonObject():New()
Local oCoreDash := CoreDash():New()

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

aItems := oCoreDash:SetPOHeader(aFields)

oResponse["items"]      := aItems

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

Sintaxis:

CoreDash():SetPOCombo(aOptions)

Descripción:

Método responsable por devolver un Array de acuerdo con lo esperado en la propiedad p-options del componente Combo de la biblioteca de componentes PO-UI.

Parámetros:

Nombre

Tipo

Descripción

Estándar

Obligatorio

Referencia

aOptions

Array

Array de dos dimensiones con las siguientes informaciones:

aOptions[n, 1] = Valor (Value)

aOptions[n, 2] = Rótulo (Label)


X


Ejemplo de utilización
Local oCoreDash := CoreDash():New() 
Local aOptions	 := {}

aAdd(aOptions, {"phone"		,"Teléfono"	})
aAdd(aOptions, {"cellPhone"	,"Celular"	})

oCoreDash:SetPOCombo(aOptions)

Sintaxis:

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

Descripción:

Método responsable por construir un Formulario utilizando como base el componente DynamicForm de la biblioteca de PO-UI.

Parámetros:

Nombre

Tipo

Descripción

Estándar

Obligatorio

Referencia

cDivider

Carácter

Crea una división entre los campos, utilizando el nombre definido en la propiedad cDivider.




cProperty

Carácter

Nombre de la propiedad.




cGridColumns

Carácter

Número de columnas ocupado por el campo.




cLabel

Carácter

Rótulo/Label del campo.




lRequired

Lógico

Define si el campo es obligatorio.




cType

Carácter

Tipo del campo.




aOptions

Array

Lista de opciones del campo.




loptionsMulti

Carácter

Define si el campo es MultSelect.




Ejemplo de utilización
Local oResponse   := JsonObject():New()
Local oCoreDash  := CoreDash():New()

oCoreDash:SetPOForm("Tipo de gráfico", "graphictype"     , 6  , "Tipo de gráfico"    , .T., "string", oCoreDash:SetPOCombo({{"pie","Pizza"},{"polarArea","Radar"}}))
oCoreDash:SetPOForm("Filtros"        , "typesearchcombo" , 12 , "Tipo de búsqueda"   , .T., "string", oCoreDash:SetPOCombo({{"mensal","Mensal"},{"anual","Anual"}}))
oCoreDash:SetPOForm(""               , "datadereferencia", 6  , "Fecha de referencia" , .T., "date")

oResponse  := oCoreDash:GetPOForm()

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

Sintaxis:

CoreDash():GetPOForm()

Descripción:

Método responsable por devolver el Formulario, construido por medio del método SetPOForm.

Ejemplo de utilización
Local oResponse   := JsonObject():New()
Local oCoreDash  := CoreDash():New()

oCoreDash:SetPOForm("Tipo de gráfico", "graphictype"     , 6  , "Tipo de gráfico"    , .T., "string", oCoreDash:SetPOCombo({{"pie","Pizza"},{"polarArea","Radar"}}))
oCoreDash:SetPOForm("Filtros"        , "typesearchcombo" , 12 , "Tipo de búsqueda"   , .T., "string", oCoreDash:SetPOCombo({{"mensal","Mensal"},{"anual","Anual"}}))
oCoreDash:SetPOForm(""               , "datadereferencia", 6  , "Fecha de referencia" , .T., "date")

oResponse  := oCoreDash:GetPOForm()

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

Sintaxis:

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

Descripción:

Método responsable por incluir líneas y/o columnas en un Gráfico de Barra o Línea.

Parámetros:

Nombre

Tipo

Descripción

Estándar

Obligatorio

Referencia

aDados

Carácter

Array de Valores utilizados en el gráfico.


X


cLegenda

Carácter

Leyenda Label de la serie del gráfico.


X


cTipo

Carácter

Tipo de la serie en el gráfico. Ejemplos: bar, line




cBgColor

Carácter

Color de la serie.




lBackGround

Lógico

Define si el gráfico de líneas tendrá color de fondo.

.F.



lDrillDown

Carácter

Define si la serie permite drilldown.

.T.



Ejemplo de utilización
Local oCoreDash  := CoreDash():New()
Local aHeader	  := {"2019","2020","2021"}
Local aData1	  := { Randomize(1,99), Randomize(1,99), Randomize(1,99) }
Local aData2	  := { Randomize(1,99), Randomize(1,99), Randomize(1,99) }
Local aSaldo	  := {}
Local nSaldo	  := 0

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

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

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

Sintaxis:

CoreDash():GetChartInfo()

Descripción:

Método responsable por devolver todos los gráficos incluidos por medio del método SetChartInfo.

Ejemplo de utilización
Local aGraphic 	  := {}
Local oCoreDash  := CoreDash():New()

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

Sintaxis:

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

Descripción:

Método responsable por devolver todas las informaciones de gráficos de Barra/Linha.

Parámetros:

Nombre

Tipo

Descripción

Estándar

Obligatorio

Referencia

aLegenda

Array

Leyendas mostradas nen el Gráfico


X


aDados

Array

Datos impresos en el Gráfico.

Observación: Para gráficos del tipo barra/línea, puede utilizarse el propio GetChartInfo




lCurrency

Lógico

Informa si la máscara devuelta será o no del tipo moneda

.F.



cType

Carácter

Tipo de gráfico que será devuelto.




cTitle

Carácter

Título mostrado en el gráfico.




aMaskFrac

Array

Informa los formatos de máscara que pueden transferirse 




Atención

Para los gráficos del tipo Pizza y Polar no es posible realizar la máscara monetaria por medio de los parámetros lCurrency y aMaskFrac.

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

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

oCoreDash:SetChart(aCab,aData,lCurrency,cType,"Factura por Estado/Prov/Reg",aMask)
  

Sintaxis:

CoreDash():GetCposLGPD()

Descripción:

Método responsable por devolver array con los campos sensibles que deben tener exhibición restringida de acuerdo con el Usuario conectado.

Ejemplo de utilización
Local oCoreDash := CoreDash():New() 
Local aCampos 	:= {}
Local aCposLGPD	:= {} 
 
Aadd(aCampos, {"code", "A1_CODIGO"}) 
Aadd(aCampos, {"name", "A1_NOME"}) 

oCoreDash:SetFields(aCampos) 

aCposLGPD := oCoreDash:GetCposLGPD()

Sintaxis:

CoreDash():GetColorChart()

Descripción:

Método responsable por devolver en un array todos los colores estandarizados para uso de gráficos DASH.

Si se transfiriera al método el ID del color, se devolverá solamente el color solicitado.

CoreDash():GetColorChart(X);

Donde X es el ID del color solicitado.

Parámetros:

Color (Variable)

Descripción del color

ID

Código RGBA

Situación Array

Ejemplo color

cGreenDk

Verde oscuro

1

rgba( 0,178,142, 1)

aArray[1][3]

cGreenLht

Verde claro

2

rgba( 0,201,161, 1)

aArray[2][3]

cRedDk

Rojo oscuro

3

rgba(198, 72, 64, 1)

aArray[3][3]

cRedLht

Rojo claro

4

rgba(227, 73, 64, 1)

aArray[4][3]

cYellDk

Amarillo oscuro

5

rgba(252,203, 76, 1)

aArray[5][3]

cYellLht

Amarillo claro

6

rgba(255,212,100, 1)

aArray[6][3]

cOrangeDk

Anaranjado oscuro

7

rgba(234,155, 62, 1)

aArray[7][3]

cOrangeLht

Anaranjado claro

8

rgba(255,162, 54, 1)

aArray[8][3]

cBlueDk

Azul oscuro

9

rgba( 0,120,255, 1)

aArray[9][3]

cBlueLht

Azul claro

10

rgba( 50,165,255, 1)

aArray[10][3]

cGreyDk

Gris oscuro

11

rgba(192,192,192, 1)

aArray[11][3]

cGreyLht

Gris claro

12

rgba(200,200,210, 1)

aArray[12][3]

cPurpleDk

Morado oscuro

13

rgba(128, 0,128, 1)

aArray[13][3]

cPurpleLht

Morado claro

14

rgba(185, 35,185, 1)

aArray[14][3]

cBrownDk

Marrón oscuro

15

rgba(128, 0, 0, 1)

aArray[15][3]

cBrownLht

Marrón claro

16

rgba(160, 80, 40, 1)

aArray[16][3]

cFuchsiaDk

Fucsia oscuro

17

rgba(255, 0,255, 1)

aArray[17][3]

cFuchsiaLht

Fucsia claro

18

rgba(255,120,255, 1)

aArray[18][3]

cMnightBlue

Azul media noche

19

rgba( 25, 25,112, 1)

aArray[19][3]

cMediumBlue

Azul medio

20

rgba( 0, 0,205, 1)

aArray[20][3]

cDGreen

Verde

21

rgba( 0,100, 0, 1)

aArray[21][3]

cFGreen

Verde selva

22

rgba( 34,139, 34, 1)

aArray[22][3]

cGreenYel

Verde limón

23

rgba(173,255, 47, 1)

aArray[23][3]

cSalmon

Salmón

24

rgba(250,128,114, 1)

aArray[24][3]

cTan

Rosado quemado

25

rgba(210,180,140, 1)

aArray[25][3]

cWheat

Rosado trigo

26

rgba(245,222,179, 1)

aArray[26][3]

cSlateGray

Gris pizarra

27

rgba(112,128,144, 1)

aArray[27][3]

cMistyRose

Rosa claro

28

rgba(255,228,225, 1)

aArray[28][3]

04. OTRAS INFORMACIONES

  • No hay.