Cayaqui.MPS.WordExport 0.3.1

dotnet add package Cayaqui.MPS.WordExport --version 0.3.1
                    
NuGet\Install-Package Cayaqui.MPS.WordExport -Version 0.3.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Cayaqui.MPS.WordExport" Version="0.3.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Cayaqui.MPS.WordExport" Version="0.3.1" />
                    
Directory.Packages.props
<PackageReference Include="Cayaqui.MPS.WordExport" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Cayaqui.MPS.WordExport --version 0.3.1
                    
#r "nuget: Cayaqui.MPS.WordExport, 0.3.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Cayaqui.MPS.WordExport@0.3.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Cayaqui.MPS.WordExport&version=0.3.1
                    
Install as a Cake Addin
#tool nuget:?package=Cayaqui.MPS.WordExport&version=0.3.1
                    
Install as a Cake Tool

Cayaqui.MPS.WordExport

Genera documentos Word (.docx) para reportes EVM programáticamente, usando Syncfusion.DocIO. Cada sección implementa IWordDocSection y agrega una sección paginada a un WordDocument existente. Todas las secciones aplican estilo Heading1 para que Word genere automáticamente la Tabla de Contenido.

Distribución propietaria — requiere contrato comercial con Cayaqui. Ver LICENSE.txt.

Dependencias: Cayaqui.MPS.ReportModels (DTOs y paleta MPS) + licencia Syncfusion DocIO.


v0.3.0 — CoverPageDocSection: portada corporativa Word

Nueva sección CoverPageDocSection que genera una portada profesional completa usando WTable. Diseño: barra accent superior → 3 columnas logos → título / proyecto → info table (proyecto, empresa, responsable, fecha, versión, clasificación) → logo Cayaqui footer.

Se activa con WordReportOptions.Logos (nuevo en esta versión):

var logos = new LogoOptions
{
    OwnerLogo        = new BytesLogo { Bytes = ownerLogoBytes },
    MpsLogo          = new BytesLogo { Bytes = mpsProductLogoBytes },
    MpsCompanyLogo   = new BytesLogo { Bytes = cayaquiLogoBytes }
};

var opts = new WordReportOptions { Theme = theme, Logos = logos };

await new WordReport()
    .AddCoverPage()            // portada corporativa
    .AddTableOfContents()
    .AddEvmKpiStrip(kpis)
    .BuildAsync(stream, opts, ct);

Setup

1 — Agregar el package

<PackageReference Include="Cayaqui.MPS.WordExport" Version="0.3.0" />

Con Central Package Management (Directory.Packages.props):


<PackageVersion Include="Cayaqui.MPS.WordExport" Version="0.1.5" />


<PackageReference Include="Cayaqui.MPS.WordExport" />

2 — Registrar la licencia Syncfusion

En Program.cs, antes de var builder = WebApplication.CreateBuilder(args):

Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense(
    Environment.GetEnvironmentVariable("SYNCFUSION_LICENSE_KEY")
    ?? builder.Configuration["Syncfusion:LicenseKey"]
    ?? throw new InvalidOperationException("Falta SYNCFUSION_LICENSE_KEY"));

Si ya registrás la licencia para otros paquetes Syncfusion (ej: Blazor), no repitas la llamada — una sola cubre toda la suite.

Local dev: dotnet user-secrets set "Syncfusion:LicenseKey" "<KEY>"
CI/Prod: env var SYNCFUSION_LICENSE_KEY o Azure Key Vault.

3 — Registrar en DI

using MPS.Infrastructure.WordExport;

builder.Services.AddMpsWordExport(
    licenseKey: builder.Configuration["MPS:WordExportLicenseKey"]
                ?? Environment.GetEnvironmentVariable("MPS_WORD_EXPORT_LICENSE_KEY"));

Esto registra como singleton:

  • IWordReportContextWordReportContext (opciones default; ver sección "Opciones" para personalizar)
  • IWordReportExporterWordReportExporter

Sin licenseKey válida, el footer de cada sección del .docx muestra texto en rojo. Con licencia, muestra texto gris discreto.

4 — Usings (Blazor)

En _Imports.razor:

@using MPS.Infrastructure.WordExport
@using MPS.Infrastructure.WordExport.Evm
@using MPS.Infrastructure.ReportModels.Evm

Uso

Web API — endpoint de descarga

app.MapGet("/api/reports/evm", async (IWordReportExporter exporter, CancellationToken ct) =>
{
    var report = new WordReport()
        .AddTitle("Reporte EVM — Proyecto Demo", "Período Mayo 2026")
        .AddTableOfContents()
        .AddEvmKpiStrip(new EvmKpiStripDocSection
        {
            Snapshot = new EvmKpiSnapshot(
                Ev: 4_500_000m, Pv: 5_000_000m, Ac: 4_800_000m,
                Bac: 20_000_000m, Eac: 21_333_333m,
                PrevEv: 4_000_000m, PrevPv: 4_500_000m, PrevAc: 4_300_000m)
        })
        .AddEvmSCurveChart(new EvmSCurveChartDocSection
        {
            Points = [
                new(new DateTime(2026, 1, 1), Pv: 1_000_000m, Ev:   900_000m, Ac:   950_000m),
                new(new DateTime(2026, 2, 1), Pv: 2_500_000m, Ev: 2_200_000m, Ac: 2_400_000m),
                new(new DateTime(2026, 3, 1), Pv: 4_000_000m, Ev: 3_500_000m, Ac: 3_700_000m),
                new(new DateTime(2026, 4, 1), Pv: 5_000_000m, Ev: 4_500_000m, Ac: 4_800_000m),
            ],
            Bac         = 20_000_000m,
            ControlDate = new DateTime(2026, 4, 30),
        })
        .AddMilestoneStrip(new MilestoneStripDocSection
        {
            Milestones = [
                new("Ingeniería 30%",  new DateTime(2026, 2, 28), MilestoneHealth.Done),
                new("Ingeniería 60%",  new DateTime(2026, 4, 30), MilestoneHealth.OnTime),
                new("Procura crítica", new DateTime(2026, 6, 30), MilestoneHealth.AtRisk, Critical: true),
            ]
        });

    await using var stream = await exporter.ExportAsync(report, ct);
    var bytes = ((MemoryStream)stream).ToArray();
    return Results.File(bytes,
        contentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
        fileDownloadName: $"evm-{DateTime.Today:yyyy-MM-dd}.docx");
});

Blazor — botón de descarga

@inject IWordReportExporter WordExporter
@inject IJSRuntime JS

<button @onclick="Descargar">Descargar Word</button>

@code {
    private async Task Descargar()
    {
        var report = new WordReport()
            .AddTitle("Reporte EVM", "Mayo 2026")
            .AddTableOfContents()
            .AddEvmKpiStrip(new EvmKpiStripDocSection { Snapshot = ... });

        await using var stream = await WordExporter.ExportAsync(report);
        var bytes = ((MemoryStream)stream).ToArray();
        using var dotnetStream = new DotNetStreamReference(new MemoryStream(bytes));
        await JS.InvokeVoidAsync("downloadFileFromStream",
            $"reporte-{DateTime.Today:yyyy-MM-dd}.docx",
            dotnetStream);
    }
}

Helper JS en wwwroot/js/download.js:

window.downloadFileFromStream = async (fileName, streamRef) => {
    const bytes = await streamRef.arrayBuffer();
    const blob = new Blob([bytes], { type: "application/octet-stream" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url; a.download = fileName; a.click();
    URL.revokeObjectURL(url);
};

<script src="js/download.js"></script>

Opciones de estilo

Para personalizar colores de encabezados de tabla y accent de gráficos, reemplazá el registro default:

builder.Services.AddMpsWordExport(licenseKey: "...");

// Sobrescribir el contexto con opciones custom
builder.Services.AddSingleton<IWordReportContext>(_ =>
    new WordReportContext(new WordReportOptions
    {
        HeaderBackgroundColor = "#0D3349",
        AccentColor           = "#1E6FBF",
        Typography = new WordTypographyOptions
        {
            BodyFontName    = "Calibri",
            TableFontName   = "Calibri",
            NumericFontName = "Consolas",
        }
    }));

Secciones disponibles

Tablas

Sección Output Contenido
TitleDocSection párrafo Título + subtítulo del informe.
TableOfContentsDocSection campo TOC Tabla de contenido automática.
EvmKpiStripDocSection tabla 8 cols CPI/SPI/EV/AC/PV/BAC/EAC/VAC. Semáforo + fila delta.
R9cTableDocSection tabla 11 cols Reporte 9 columnas AACE 80R-13 con variance coloring.
RiskHeatmapDocSection tabla grid 5×5 + tabla anexo Score coloring + listado de riesgos.
ScheduleVarianceDocSection tabla Baseline/Current/Forecast + SV días.
MilestoneStripDocSection tabla 5 cols Hitos coloreados por MilestoneHealth.
ChangeOrderLogDocSection tabla 8 cols Log de órdenes de cambio.
RiskRegisterTableDocSection tabla 9 cols Registro de riesgos con score coloring.
WaterfallDocSection tabla 3 cols Cascada Label/Valor/Acumulado por WaterfallStepKind.
ManagementReserveTrackerDocSection tabla + line chart Eventos de reserva + gráfico de balance.
WbsBudgetTableDocSection tabla 9 cols WBS jerárquico con BAC/EV/AC/EAC/CV/CPI/% Done. CPI=EV/AC. Indenta por Level.
EngProgressTableDocSection tabla 8 cols Code/Title/Discipline, Plan%/Actual%/Desviación, Planned Date/Forecast Date. Desviación en verde/rojo.
LookaheadTableDocSection tabla 7 cols WBS/Activity/Responsible/Start/Finish, LookaheadStatus con coloring, Comments.
RaciMatrixDocSection tabla pivot Actividades × Roles. R=azul, A=púrpura, C=ámbar, I=neutro.
PoRegisterDocSection tabla 7 cols PO#/Supplier/Description/Amount/Status/Issue Date/Delivery Date.

Gráficos

Sección Chart Contenido
EvmSCurveChartDocSection line PV/EV/AC/Forecast + líneas BAC y ControlDate.
CashflowChartDocSection column + line Columnas Plan/Actual/Forecast + acumuladas opcionales.
BurndownChartDocSection line Remaining + Ideal calculado.
PhysicalProgressCurveDocSection line % Baseline/Plan/Actual/Forecast.
ProductionCurveDocSection line Plan/Actual + NameplateRate opcional.
MonteCarloHistogramDocSection column Bins + summary stats (N, P50/P80/P90).
ContingencyDrawdownDocSection line Contingencia restante Plan vs Actual.
TornadoChartDocSection bar horizontal Low/High deviations por factor de riesgo.
ResourceHistogramDocSection column stacked Period × Category + Capacity line opcional.
EvmControlChartDocSection line SV (ámbar) y CV (azul) en el tiempo.

Secciones custom

Implementá IWordDocSection para agregar tus propias secciones al flujo:

public sealed class FirmasDocSection : IWordDocSection
{
    public Task RenderAsync(WordDocument document, IWordReportContext context,
        CancellationToken ct = default)
    {
        var body = context.AddSection(document);

        var heading = (WParagraph)body.AddParagraph();
        heading.ApplyStyle(BuiltinStyle.Heading1);
        heading.AppendText("Firmas y Aprobaciones");

        // ... agregar tabla de firmas
        return Task.CompletedTask;
    }
}

// Uso en el builder
var report = new WordReport()
    .AddTitle("Mi Reporte")
    .AddTableOfContents();

report.Sections.Add(new FirmasDocSection());  // sección custom al final

Notas técnicas

  • Cada sección agrega un WSection con SectionBreakCode.NewPage (excepto la primera).
  • Los encabezados usan BuiltinStyle.Heading1 para el outline de TOC automático.
  • WordReportExporter llama UpdateDocumentFields() antes de guardar — el TOC se resuelve automáticamente. En LibreOffice, actualizar manualmente al abrir.
  • Colores de series line: usar SerieFormat.LineProperties.LineColor. SerieFormat.Fill.ForeColor aplica sólo a series Column/Bar.
  • El helper JS downloadFileFromStream espera 2 argumentos: (fileName, streamRef) — no pasar contentType como tercer argumento.
  • El footer de cada sección lleva texto de watermark: gris con licencia válida, rojo sin ella.
  • Target framework: net10.0. No compatible con .NET 9 o anterior.

Release Notes

0.2.0

WordReportOptions ahora expone Theme (tipo ReportTheme de Cayaqui.MPS.ReportModels). Permite compartir el mismo objeto de branding entre los tres formatos de export:

var theme = new ReportTheme
{
    ReportTitle          = "Monthly Project Report",
    ProjectName          = "Talara U3 — Expansion",
    CompanyName          = "Cayaqui S.A.",
    PreparedBy           = "Project Controls Team",
    ReportDate           = new DateTime(2026, 4, 30),
    ConfidentialityLabel = "CONFIDENCIAL",
    PrimaryColorHex      = "#0F2044",
    AccentColorHex       = "#C9961A"
};

// Word
builder.Services.AddSingleton<IWordReportContext>(_ =>
    new WordReportContext(new WordReportOptions
    {
        Theme                 = theme,
        HeaderBackgroundColor = theme.PrimaryColorHex,
        AccentColor           = theme.AccentColorHex
    }));

// Excel — mismo objeto theme
var excelStream = await excelExporter.ExportAsync(report, new ExcelExportOptions { Theme = theme });

Theme es null por default — comportamiento legacy sin cambios. Las secciones Word existentes usan HeaderBackgroundColor / AccentColor directamente; Theme está disponible para CoverPageDocSection y flujos de branding centralizado en versiones futuras.


0.1.4

WaterfallDocSection: declaraciones de color refactorizadas para usar constantes de EvmChartPalette (WaterfallTotal, WaterfallSubtotal, Earned, Actual, Cyan, Amber). Sin cambio de comportamiento — mismos valores hex. Requiere Cayaqui.MPS.ReportModels ≥ 0.3.4.

0.1.3

6 nuevas secciones EPC: WbsBudgetTableDocSection (9 cols, CPI=EV/AC, indentación WBS), EngProgressTableDocSection (8 cols, desviación coloreada), LookaheadTableDocSection (7 cols, LookaheadStatus), EvmControlChartDocSection (SV/CV line chart), RaciMatrixDocSection (pivot Activity×Role con RACI coloring), PoRegisterDocSection (7 cols). Requiere Cayaqui.MPS.ReportModels ≥ 0.3.3.

0.1.2

Fix TypeLoadException en despliegues IIS con múltiples paquetes MPS (WordLicenseState no encontrado). Solución: MPS.Licensing.dll bumped a AssemblyVersion 2.0.0.0 — .NET siempre carga la versión más alta cuando múltiples copies están presentes.

0.1.1

Initial release con 20 secciones (10 tablas + 9 gráficos + TOC). Setup vía AddMpsWordExport(licenseKey).

0.1.0

Scaffold: contratos IWordDocSection, IWordReportContext, IWordReportExporter, WordReport builder fluido.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.3.1 97 5/26/2026
0.3.0 80 5/26/2026
0.1.5 165 5/19/2026
0.1.4 81 5/19/2026
0.1.3 84 5/19/2026
0.1.2 92 5/19/2026
0.1.1 82 5/19/2026
0.1.0 92 5/19/2026

0.3.1 — CoverPageDocSection: logo aspect ratio preserved (fit-within maxW×maxH without distortion). 0.3.0 — CoverPageDocSection corporate Word cover; WordReportOptions.Logos; WordReport.AddCoverPage(). 0.1.5 — R9cTableDocSection: esquema R9C actualizado (Incurrido/Pagado/Trends/EAC). Requiere ReportModels ≥ 0.3.5. 0.1.4 — WaterfallDocSection: color declarations refactored to use EvmChartPalette constants (WaterfallTotal, WaterfallSubtotal, Earned, Actual, Cyan, Amber). No behavioral change; guarantees color parity with web design system and ReportModels palette. Requires Cayaqui.MPS.ReportModels >= 0.3.4.

0.1.3 — 6 new doc sections: WbsBudgetTableDocSection, EngProgressTableDocSection, LookaheadTableDocSection, EvmControlChartDocSection (SV/CV line chart), RaciMatrixDocSection (pivot table), PoRegisterDocSection. 6 new fluent builder methods on WordReport.
0.1.2 — fix: bump MPS.Licensing assembly version to 2.0.0.0 so .NET picks the correct version when multiple Cayaqui.MPS.* packages bundle different copies of MPS.Licensing.dll (TypeLoadException on WordLicenseState).
0.1.1 — docs: expand PackageReadme with full consumer setup guide (DI registration, Web API + Blazor download examples, custom sections, style options). No code changes.
0.1.0 — Scaffold: IWordDocSection, IWordReportContext, WordReportContext, WordReportOptions, WordReport, WordReportExporter. 20 EVM doc sections (19 EVM + TOC). Heading outline for auto-generated Table of Contents.