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
<PackageReference Include="Cayaqui.MPS.WordExport" Version="0.3.1" />
<PackageVersion Include="Cayaqui.MPS.WordExport" Version="0.3.1" />
<PackageReference Include="Cayaqui.MPS.WordExport" />
paket add Cayaqui.MPS.WordExport --version 0.3.1
#r "nuget: Cayaqui.MPS.WordExport, 0.3.1"
#:package Cayaqui.MPS.WordExport@0.3.1
#addin nuget:?package=Cayaqui.MPS.WordExport&version=0.3.1
#tool nuget:?package=Cayaqui.MPS.WordExport&version=0.3.1
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:
IWordReportContext→WordReportContext(opciones default; ver sección "Opciones" para personalizar)IWordReportExporter→WordReportExporter
Sin
licenseKeyválida, el footer de cada sección del.docxmuestra 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
WSectionconSectionBreakCode.NewPage(excepto la primera). - Los encabezados usan
BuiltinStyle.Heading1para el outline de TOC automático. WordReportExporterllamaUpdateDocumentFields()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.ForeColoraplica sólo a series Column/Bar. - El helper JS
downloadFileFromStreamespera 2 argumentos:(fileName, streamRef)— no pasarcontentTypecomo 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 | Versions 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. |
-
net10.0
- Cayaqui.MPS.Metadata (>= 0.18.0)
- Cayaqui.MPS.ReportModels (>= 0.4.0)
- Cayaqui.MPS.Storage (>= 0.2.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.7)
- Syncfusion.DocIO.Net.Core (>= 33.2.3)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
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.