Fondos humanitarios para Cuba

Flujos de fondos de OCHA Financial Tracking Service (FTS)

Flujos entrantes—
Dentro del plan—
Fuera del plan—
% dentro del plan—
Total FTS—

Proporción dentro/fuera del plan

Porcentajes sobre el total oficial de fondos entrantes reportado por FTS.

Monto por relación con el plan

Montos entrantes repartidos entre fondos dentro y fuera del plan.

Requerimiento del plan y fondos recibidos

Haz clic en una fila para filtrar las tres tablas, los indicadores y el detalle de flujos; haz clic de nuevo para quitar el filtro. El filtro maestro controla si se muestran fondos dentro, fuera o ambos. FTS publica requerimientos por sector, pero no por donante ni receptora. Si un flujo tiene varias categorías, su monto se distribuye en partes iguales; esa desagregación es referencial.

Fondos por sector

Sector Requerimiento Dentro del plan Financiado Fuera del plan Total financiado
Cargando análisis del plan...

Fondos por donante

Donante Dentro del plan Fuera del plan Total financiado
Cargando análisis del plan...

Fondos por organización receptora

Receptora Dentro del plan Fuera del plan Total financiado
Cargando análisis del plan...
Metodología de los indicadores

Sin selección cruzada, los montos siguen el total oficial de FTS: suma los flujos entrantes vinculados a un Plan y los flujos internos vinculados al plan que no tienen año presupuestario; “fuera del plan” es el resto del total oficial. Al seleccionar un donante, sector o agencia, los indicadores se recalculan con los flujos coincidentes y sus montos positivos de amountUSD; son estimaciones analíticas y pueden diferir del total oficial. Si un flujo tiene varios sectores, aparece en varias filas de la tabla, con el monto total una sola vez.

Detalle de flujos — tabla complementaria

Año ID flujo Flujo Donante / origen Receptor Plan de acción Sector Monto (US$) Estado Dirección Relaciones

Fuente: . País: Cuba (CUB; ID 57 en FTS). Los registros y totales pueden cambiar cuando OCHA actualice la fuente.

Usar la API de FTS en Power BI

La consulta siguiente crea una tabla con las mismas columnas y relaciones que el panel, con Año como campo filtrable.

  1. En Power BI Desktop, selecciona Transformar datos → Nueva fuente → Consulta en blanco.
  2. Abre Editor avanzado, reemplaza el contenido con el código de abajo y pulsa Listo.
  3. Para consultar un solo año, cambia Anios = {2025, 2026} por Anios = {2025} o Anios = {2026}. Deja ambos para combinarlos.
  4. Cuando Power BI solicite credenciales para https://api.hpc.tools, selecciona Anónimo y aplica la configuración al nivel del sitio.
  5. Pulsa Cerrar y aplicar. En el informe, añade un segmentador con Año y un visual de tabla con las columnas siguientes. Usa la medida de financiación única para los totales.

Columnas de la tabla: Año, ID flujo, Flujo, Donante / origen, Receptor, Plan de acción, Sector, Monto (US$), Estado, Dirección y Relaciones.

Tipo de cluster: la consulta usa GlobalCluster por defecto, igual que el panel. Para usar los field clusters, cambia TipoCluster = "GlobalCluster" por TipoCluster = "Cluster" en el Editor avanzado.

Importante: un flujo con varios sectores aparece en varias filas; el monto se incluye solo en la primera fila de ese flujo y queda vacío en las demás. El API no informa un monto individual por sector. Power BI no admite celdas combinadas como las de esta tabla HTML.

Filtro por año: si un ID aparece en las respuestas de varios años, la consulta lo conserva una vez por cada año para que el segmentador Año funcione. Para que los totales al seleccionar varios años no vuelvan a sumar el mismo ID, crea esta medida y úsala en los visuales en lugar de sumar directamente la columna Monto (US$). Si el nombre de la consulta es distinto, reemplaza FlujosFTS por ese nombre:

Financiación única (US$) =
SUMX(
    VALUES(FlujosFTS[ID flujo]),
    CALCULATE(MAX(FlujosFTS[Monto (US$)]))
)
let
    Anios = {2025, 2026},
          TipoCluster = "GlobalCluster",
          BaseUrl = "https://api.hpc.tools",

    CargarAnio = (Anio as number) as list =>
        let
            Respuesta = Json.Document(
                Web.Contents(
                    BaseUrl,
                    [
                        RelativePath = "v1/public/fts/flow",
                        Query = [countryISO3 = "CUB", year = Text.From(Anio)]
                    ]
                )
            ),
            Flujos = Respuesta[data][flows],
            ConAnio = List.Transform(
                Flujos,
                (Flujo) => Record.AddField(Flujo, "AnioConsulta", Anio)
            )
        in
            ConAnio,

    Datos = Table.FromRecords(
        List.Combine(List.Transform(Anios, each CargarAnio(_))),
        {
            "id", "flowType", "sourceObjects", "destinationObjects", "amountUSD",
            "fullParkedAmountUSD", "status", "boundary", "parentFlowId",
            "childFlowIds", "description", "AnioConsulta"
        },
        MissingField.UseNull
    ),
    Agrupados = Table.Group(
        Datos,
        {"id", "AnioConsulta"},
        {{"Registros", each _, type table}}
    ),
    ConFlujo = Table.AddColumn(Agrupados, "RegistroFlujo", each Table.First([Registros])),

    Campo = (Registro as any, Nombre as text) as any =>
        try Record.Field(Registro, Nombre) otherwise null,
    Nombres = (Objetos as any, Tipo as text) as list =>
        if not Value.Is(Objetos, type list) then
            {}
        else
            List.Distinct(
                List.RemoveNulls(
                    List.Transform(
                        List.Select(Objetos, each Campo(_, "type") = Tipo),
                        each Campo(_, "name")
                    )
                )
            ),
    TraducirSector = (Sector as text) as text =>
        let
            Mapa = [
                #"food security" = "Seguridad Alimentaria y Nutrición",
                nutrition = "Seguridad Alimentaria y Nutrición",
                health = "Salud",
                #"water sanitation hygiene" = "Agua, Saneamiento e Higiene",
                #"emergency shelter and nfi" = "Albergues y Vivienda",
                education = "Educación",
                logistics = "Logística",
                #"energy working group" = "Grupo de Trabajo de Energía",
                #"early recovery" = "Recuperación Temprana",
                other = "Otros",
                #"multi-sector" = "Multisectorial",
                #"coordination and support services" = "Coordinación y servicios de apoyo"
            ]
        in
            Record.FieldOrDefault(Mapa, Text.Lower(Sector), Sector),

    ConFilas = Table.AddColumn(
        ConFlujo,
        "FilasTabla",
        each
            let
                Flujo = [RegistroFlujo],
                Origenes = Nombres(Campo(Flujo, "sourceObjects"), "Organization"),
                Receptores = Nombres(Campo(Flujo, "destinationObjects"), "Organization"),
                Planes = Nombres(Campo(Flujo, "destinationObjects"), "Plan"),
                SectoresOriginales = Nombres(Campo(Flujo, "destinationObjects"), TipoCluster),
                SectoresSeleccionados = if TipoCluster = "GlobalCluster" then
                    List.Transform(SectoresOriginales, each TraducirSector(_))
                else
                    SectoresOriginales,
                Sectores = if List.Count(SectoresSeleccionados) > 0 then
                    SectoresSeleccionados
                else
                    {"No informado"},
                EstadoOriginal = Campo(Flujo, "status"),
                Estado = if EstadoOriginal = "paid" then "Pagado"
                    else if EstadoOriginal = "commitment" then "Compromiso"
                    else if EstadoOriginal = "pledge" then "Promesa"
                    else EstadoOriginal,
                DireccionOriginal = Campo(Flujo, "boundary"),
                Direccion = if DireccionOriginal = "incoming" then "Entrada"
                    else if DireccionOriginal = "internal" then "Interno"
                    else if DireccionOriginal = "outgoing" then "Salida"
                    else DireccionOriginal,
                Clasificacion = if List.Count(Planes) > 0 then "Dentro del plan" else "Fuera del plan",
                PlanTexto = if List.Count(Planes) > 0 then
                    Clasificacion & "#(lf)" & Text.Combine(Planes, "; ")
                else
                    Clasificacion,
                MontoNormal = Campo(Flujo, "amountUSD"),
                MontoAparcado = Campo(Flujo, "fullParkedAmountUSD"),
                Monto = if MontoNormal <> null and MontoNormal <> 0 then MontoNormal
                    else if MontoAparcado <> null then MontoAparcado
                    else 0,
                AnioFila = Text.From([AnioConsulta]),
                IdFlujo = Text.From(Campo(Flujo, "id")),
                FlujoTexto = "#" & Text.From(Campo(Flujo, "id"))
                    & " · " & Text.From(Campo(Flujo, "flowType")),
                IdPadre = Campo(Flujo, "parentFlowId"),
                IdsHijos = Campo(Flujo, "childFlowIds"),
                RelacionesBase = List.RemoveNulls({
                    if IdPadre <> null then "Padre: #" & Text.From(IdPadre) else null,
                    if Value.Is(IdsHijos, type list) and List.Count(IdsHijos) > 0 then
                        "Hijos: " & Text.Combine(List.Transform(IdsHijos, each "#" & Text.From(_)), ", ")
                    else
                        null
                }),
                Relaciones = Text.Combine(
                    List.Combine({
                        if List.Count(RelacionesBase) > 0 then {Text.Combine(RelacionesBase, " · ")}
                        else {"Sin vínculo padre/hijo"},
                        if Campo(Flujo, "description") <> null then {Text.From(Campo(Flujo, "description"))}
                        else {}
                    }),
                    "#(lf)"
                ),
                Filas = List.Transform(
                    List.Positions(Sectores),
                    (Indice) => [
                        #"Año" = AnioFila,
                        #"ID flujo" = IdFlujo,
                        Flujo = FlujoTexto,
                        #"Donante / origen" = if List.Count(Origenes) > 0 then Text.Combine(Origenes, "; ") else "No informado",
                        Receptor = if List.Count(Receptores) > 0 then Text.Combine(Receptores, "; ") else "No informado",
                        #"Plan de acción" = PlanTexto,
                        Sector = Sectores{Indice},
                        #"Monto (US$)" = if Indice = 0 then Monto else null,
                        Estado = Estado,
                        Dirección = Direccion,
                        Relaciones = Relaciones
                    ]
                )
            in
                Filas,
        type list
    ),
    ExpandirLista = Table.ExpandListColumn(ConFilas, "FilasTabla"),
    ExpandirColumnas = Table.ExpandRecordColumn(
        ExpandirLista,
        "FilasTabla",
        {"Año", "ID flujo", "Flujo", "Donante / origen", "Receptor", "Plan de acción", "Sector", "Monto (US$)", "Estado", "Dirección", "Relaciones"},
        {"Año", "ID flujo", "Flujo", "Donante / origen", "Receptor", "Plan de acción", "Sector", "Monto (US$)", "Estado", "Dirección", "Relaciones"}
    ),
    Resultado = Table.SelectColumns(
        ExpandirColumnas,
        {"Año", "ID flujo", "Flujo", "Donante / origen", "Receptor", "Plan de acción", "Sector", "Monto (US$)", "Estado", "Dirección", "Relaciones"}
    ),
    Tipos = Table.TransformColumnTypes(Resultado, {{"Monto (US$)", Currency.Type}})
in
    Tipos