10 agosto, 2026

AUTOMATIZACIÓN COMPLETA CON POWER PLATFORM: DE POWER APPS A SHAREPOINT, AUTOMATE Y OFFICESCRIPT CON SINCRONIZACIÓN INTELIGENTE

Hola a todos!

Después de la última publicación, donde utilizábamos los flujos de datos para crear consultas complejas, me comentaban que el tema de las licencias premium podían suponer un problema o un bloqueo al uso de estas herramientas. Y hasta cierto punto, puede que sea así, pero no necesariamente. Imaginad que el último post: AUTOMATIZACIÓN COMPLETA CON POWER PLATFORM: DE POWER APPS A SHAREPOINT Y DATAVERSE CON SINCRONIZACIÓN INTELIGENTE lo podemos hacer con Power Automate, Excel Online y OfficeScript, que os parecería?.

Pues bien, esto es posible y lo voy a demostrar.

Tal y como comenzábamos en el post anterior, partíamos de una lista en SharePoint (SP):

Y es desde aquí donde vamos a obtener toda la información para poder obtener nuestros datos. El segundo paso que debemos hacer es crear una tabla en una ubicación de One Drive:

Y en el Excel vamos a crear las siguientes columnas:

Y ahora ya podemos comenzar a programar nuestro flujo en Power Automate.

Para facilitaros la tarea, os paso el esquema JSON utilizado en el Análisis de archivo JSON (segunda imagen del flujo):

{
    "type": "array",
    "items": {
        "type": "object",
        "properties": {
            "Proyecto": {
                "type": "string"
            },
            "Tareas Completas": {
                "type": "number"
            },
            "Tareas Pendientes": {
                "type": "number"
            },
            "Tareas Totales": {
                "type": "number"
            },
            "Tareas Vencidas": {
                "type": "number"
            },
            "Horas Estimadas": {
                "type": "number"
            },
            "Horas Reales": {
                "type": "number"
            },
            "Eficiencia Promedio": {
                "type": "number"
            },
            "% Completado": {
                "type": "number"
            },
            "% Desviación": {
                "type": "number"
            }
        }
    }
}

Y también el Script que es necesario ejecutar para que calcule todos los elementos. Aquí en lugar de lenguaje M, usamos Typescript para realizar los cálculos:


interface Task {
    Proyecto?: string;
    Estado?: string;
    FechaVencimiento?: string;
    HorasEstimadas?: number;
    HorasReales?: number;
}

// Estrucutra
interface ProjectData {
    Proyecto: string;
    TareasCompletas: number;
    TareasPendientes: number;
    TareasTotales: number;
    TareasVencidas: number;
    HorasEstimadas: number;
    HorasReales: number;
    Deviations: number[];
    Efficiencies: number[];
}


function main(workbook: ExcelScript.Workbook, tasksJSON: string): string {
    // Convertir la cadena JSON a un arreglo tipado de tareas.
    const tasks: Task[] = JSON.parse(tasksJSON);
    const hoy: Date = new Date();
    const projects: { [key: string]: ProjectData } = {};

    // Procesamos cada tarea
    for (let tarea of tasks) {
        const proyecto: string = tarea.Proyecto || "Sin Proyecto";
        if (!projects[proyecto]) {
            projects[proyecto] = {
                Proyecto: proyecto,
                TareasCompletas: 0,
                TareasPendientes: 0,
                TareasTotales: 0,
                TareasVencidas: 0,
                HorasEstimadas: 0,
                HorasReales: 0,
                Deviations: [],
                Efficiencies: []
            };
        }
        let p = projects[proyecto];
        p.TareasTotales++;

        // Clasificar según el estado de tarea
        if (tarea.Estado === "Completada") {
            p.TareasCompletas++;
        } else {
            p.TareasPendientes++;
        }

        // Verificar si la tarea está vencida (FechaVencimiento anterior a hoy y no completada).
        const fechaVencimiento: Date = new Date(tarea.FechaVencimiento || "");
        if (fechaVencimiento < hoy && tarea.Estado !== "Completada") {
            p.TareasVencidas++;
        }

        // Acumular horas.
        const horasEst = tarea.HorasEstimadas ? Number(tarea.HorasEstimadas) : 0;
        const horasReal = tarea.HorasReales ? Number(tarea.HorasReales) : 0;
        p.HorasEstimadas += horasEst;
        p.HorasReales += horasReal;

        // Calculamos desvia: (HorasReales - HorasEstimadas) / HorasEstimadas.
        if (horasEst > 0) {
            const deviation = (horasReal - horasEst) / horasEst;
            // Solo agregar valores válidos (>= 0 y <= 1e9).
            if (deviation >= 0 && deviation <= 1e9) {
                p.Deviations.push(deviation);
            }
        }

        // Calculamos eficiencia: HorasEstimadas / HorasReales.
        if (horasReal > 0) {
            const efficiency = horasEst / horasReal;
            if (efficiency >= 0 && efficiency <= 1e9) {
                p.Efficiencies.push(efficiency);
            }
        }
    }
    // Preparamos array final
    const results: Array<{
        "Proyecto": string;
        "Tareas Completas": number;
        "Tareas Pendientes": number;
        "Tareas Totales": number;
        "Tareas Vencidas": number;
        "Horas Estimadas": number;
        "Horas Reales": number;
        "Eficiencia Promedio": number | null;
        "% Completado": number | null;
        "% Desviación": number | null;
    }> = [];

    for (let key in projects) {
        const p = projects[key];

        // Calculo de indicadores (tiendo en cuenta las tareas) valor individual para cada tarea y luego hacemos promedio.
        let eficienciaPromedio: number | null = null;
        if (p.Efficiencies.length > 0) {
            const sumEff = p.Efficiencies.reduce((acc, val) => acc + val, 0);
            eficienciaPromedio = Number((sumEff / p.Efficiencies.length).toFixed(2));
        }
        let porcentajeDesviacion: number | null = null;
        if (p.Deviations.length > 0) {
            const sumDev = p.Deviations.reduce((acc, val) => acc + val, 0);
            const promedioDev = sumDev / p.Deviations.length;
            porcentajeDesviacion = Number((promedioDev * 100).toFixed(2));
        }
        let porcentajeCompletado: number | null = null;
        if (p.TareasTotales > 0) {
            const perc = (p.TareasCompletas * 100) / p.TareasTotales;
            porcentajeCompletado = Number(perc.toFixed(2));
        }

        results.push({
            "Proyecto": p.Proyecto,
            "Tareas Completas": p.TareasCompletas,
            "Tareas Pendientes": p.TareasPendientes,
            "Tareas Totales": p.TareasTotales,
            "Tareas Vencidas": p.TareasVencidas,
            "Horas Estimadas": p.HorasEstimadas,
            "Horas Reales": p.HorasReales,
            "Eficiencia Promedio": eficienciaPromedio,
            "% Completado": porcentajeCompletado,
            "% Desviación": porcentajeDesviacion
        });
    }

    // pasamos datos
    return JSON.stringify(results);
}

Y ahora con este flujo ya montado, si lo ejecutamos va a pasar la información directamente a la tabla que hemos creado en OneDrive:

Como podéis ver los datos son los que estamos esperando y son correctos. Además, aunque el flujo para este ejemplo es manual, se puede crear para ser programable, de forma que tendrá total autonomía.

No voy a volver a crear aquí una app para guardar los datos en la lista. Os dejo como referencia la del post anterior y que tenéis el enlace al inicio del post.

Y esto es todo, espero que sea de utilidad!!

Comparte este post

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información.plugin cookies

ACEPTAR
Aviso de cookies