Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
# Genera un DOCX válido (Office Open XML) con formato tipo presentación
# Uso:
# powershell -ExecutionPolicy Bypass -File tools\generate_presentacion_docx.ps1
$baseDir = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path
$outFile = Join-Path $baseDir 'Presentacion_ERP_para_cliente.docx'
function Escape-Xml([string]$text) {
if ($null -eq $text) { return '' }
return [System.Security.SecurityElement]::Escape($text)
}
function W-Paragraph([string]$text, [bool]$Bold = $false, [int]$Size = 22, [int]$After = 120, [string]$Align = 'left') {
$rPr = ''
if ($Bold) { $rPr += '' }
$rPr += ""
$pPrAlign = ''
switch ($Align) {
'center' { $pPrAlign = '' }
'right' { $pPrAlign = '' }
Default { $pPrAlign = '' }
}
$lines = $text -split "\r\n|\r|\n"
$runs = New-Object System.Text.StringBuilder
for ($i = 0; $i -lt $lines.Length; $i++) {
if ($i -gt 0) { [void]$runs.Append('') }
$escaped = Escape-Xml $lines[$i]
[void]$runs.Append('')
[void]$runs.Append($escaped)
[void]$runs.Append('')
}
return "$pPrAlign$rPr$($runs.ToString())"
}
function Title([string]$text) { W-Paragraph -text $text -Bold $true -Size 44 -After 240 -Align 'center' }
function Subtitle([string]$text) { W-Paragraph -text $text -Bold $false -Size 26 -After 180 -Align 'center' }
function H1([string]$text) { W-Paragraph -text $text -Bold $true -Size 34 -After 160 }
function H2([string]$text) { W-Paragraph -text $text -Bold $true -Size 28 -After 120 }
function Bullet([string]$text) { W-Paragraph -text ("• " + $text) -Bold $false -Size 24 -After 80 }
function PageBreak() {
return ''
}
# Contenido basado en menu.php
$modulos = @(
[pscustomobject]@{
Nombre = 'Facturación'
Pantallas = @('Facturas', 'Clientes', 'Reporte de facturas')
Enfoque = @(
'Emisión y control de facturas de venta.',
'Consulta por periodos y por cliente.',
'Soporte de reportes con exportación e impresión.'
)
},
[pscustomobject]@{
Nombre = 'Inventario'
Pantallas = @('Artículos', 'Categorías', 'Unidades de medida', 'Almacenes', 'Movimientos', 'Reporte general de artículos')
Enfoque = @(
'Catálogo de productos y clasificación por categorías.',
'Control de existencias por almacén y movimientos.',
'Estandarización con unidades de medida y reportes.'
)
},
[pscustomobject]@{
Nombre = 'Clientes y Cuentas por Cobrar (CXC)'
Pantallas = @('Clientes', 'Cargos a clientes', 'Pago de clientes', 'Estado de cuenta', 'Notas de crédito', 'Antigüedad de saldos', 'Reportes')
Enfoque = @(
'Gestión integral de cartera: cargos, cobros y notas de crédito.',
'Estado de cuenta por cliente y seguimiento de saldos.',
'Antigüedad para control de mora y cobranza.'
)
},
[pscustomobject]@{
Nombre = 'Proveedores y Cuentas por Pagar (CXP)'
Pantallas = @('Proveedores', 'Cargos a proveedores', 'Pagos a proveedores', 'Estado de cuenta', 'Notas de crédito', 'Antigüedad de saldos', 'Reportes')
Enfoque = @(
'Control de compromisos: cargos, pagos y notas de crédito.',
'Estado de cuenta por proveedor y planeación de pagos.',
'Antigüedad para priorizar obligaciones.'
)
},
[pscustomobject]@{
Nombre = 'Compras'
Pantallas = @('Cotizaciones', 'Órdenes de compra', 'Compras de mercancías', 'Proveedores', 'Reporte de compras')
Enfoque = @(
'Proceso de compras desde cotización hasta orden de compra.',
'Registro de compras y trazabilidad por proveedor.',
'Reportes para análisis de compras.'
)
},
[pscustomobject]@{
Nombre = 'Gastos'
Pantallas = @('Registro de gastos', 'Reporte de gastos')
Enfoque = @(
'Registro y clasificación de gastos operativos.',
'Reportes para análisis y control presupuestario.'
)
},
[pscustomobject]@{
Nombre = 'Bancos'
Pantallas = @('Bancos/Disponibilidad', 'Cuentas bancarias', 'Movimientos bancarios', 'Conciliación bancaria', 'Extractos', 'Importar extracto', 'Cheques', 'Reporte conciliación')
Enfoque = @(
'Control de movimientos bancarios y disponibilidad.',
'Conciliación bancaria contra extractos (importación y revisión).',
'Soporte de cheques y reportes de conciliación.'
)
},
[pscustomobject]@{
Nombre = 'Contabilidad'
Pantallas = @('Contabilidad general')
Enfoque = @(
'Registro y control contable (según configuración del sistema).',
'Soporte para reportes financieros y análisis de gestión.'
)
},
[pscustomobject]@{
Nombre = 'Activos Fijos'
Pantallas = @('Activos fijos', 'Depreciación de activos')
Enfoque = @(
'Registro, control y seguimiento de activos.',
'Cálculo y control de depreciación.'
)
},
[pscustomobject]@{
Nombre = 'Nómina y RRHH'
Pantallas = @('Nómina y Recursos Humanos')
Enfoque = @(
'Gestión de procesos de nómina y personal (según parametrización).'
)
},
[pscustomobject]@{
Nombre = 'Administración'
Pantallas = @('Usuarios', 'Empresa', 'Configuración', 'Impuestos')
Enfoque = @(
'Gestión de usuarios/roles y parámetros por empresa.',
'Configuración de impuestos y reglas generales.'
)
},
[pscustomobject]@{
Nombre = 'Reportes'
Pantallas = @('Módulo de reportes')
Enfoque = @(
'Reportes exportables a Excel e impresión para control y auditoría.'
)
}
)
$today = Get-Date -Format 'yyyy-MM-dd'
$docParts = New-Object System.Collections.Generic.List[string]
# Portada
$docParts.Add((Title 'Presentación Comercial – Sistema ERP')) | Out-Null
$docParts.Add((Subtitle 'Módulos, procesos y beneficios principales')) | Out-Null
$docParts.Add((W-Paragraph -text ("Fecha: $today") -Size 22 -After 180 -Align 'center')) | Out-Null
$docParts.Add((W-Paragraph -text 'Objetivo: presentar el alcance funcional del ERP para apoyar una decisión de compra.' -Size 22 -After 200 -Align 'center')) | Out-Null
$docParts.Add((PageBreak)) | Out-Null
# Agenda
$docParts.Add((H1 'Agenda')) | Out-Null
$docParts.Add((Bullet 'Visión general del ERP')) | Out-Null
$docParts.Add((Bullet 'Módulos principales (uno por sección)')) | Out-Null
$docParts.Add((Bullet 'Flujos clave: ventas/cobranza, compras/pagos, inventario, bancos/conciliación')) | Out-Null
$docParts.Add((Bullet 'Beneficios y siguientes pasos')) | Out-Null
$docParts.Add((PageBreak)) | Out-Null
# Visión general
$docParts.Add((H1 'Visión General')) | Out-Null
$docParts.Add((Bullet 'Plataforma integrada para operación y finanzas: ventas, compras, inventario, cartera, proveedores, bancos, contabilidad, activos y RRHH.')) | Out-Null
$docParts.Add((Bullet 'Centraliza información y reduce reprocesos (una sola fuente de datos).')) | Out-Null
$docParts.Add((Bullet 'Reportes exportables e impresión para control y toma de decisiones.')) | Out-Null
$docParts.Add((PageBreak)) | Out-Null
# Módulos
foreach ($m in $modulos) {
$docParts.Add((H1 $m.Nombre)) | Out-Null
$docParts.Add((H2 'Pantallas principales')) | Out-Null
foreach ($p in $m.Pantallas) { $docParts.Add((Bullet $p)) | Out-Null }
$docParts.Add((H2 'Qué resuelve / beneficios')) | Out-Null
foreach ($e in $m.Enfoque) { $docParts.Add((Bullet $e)) | Out-Null }
$docParts.Add((PageBreak)) | Out-Null
}
# Flujos
$docParts.Add((H1 'Flujos Clave del Sistema')) | Out-Null
$docParts.Add((H2 'Ventas y cobranza')) | Out-Null
$docParts.Add((Bullet 'Cliente → Factura → Cobro/Aplicación → Estado de cuenta → Antigüedad de saldos')) | Out-Null
$docParts.Add((H2 'Compras y pagos')) | Out-Null
$docParts.Add((Bullet 'Proveedor → Cotización/OC → Compra/Cargo → Pago → Estado de cuenta → Antigüedad')) | Out-Null
$docParts.Add((H2 'Inventario')) | Out-Null
$docParts.Add((Bullet 'Artículos/Almacenes → Movimientos → Reportes de existencias')) | Out-Null
$docParts.Add((H2 'Bancos y conciliación')) | Out-Null
$docParts.Add((Bullet 'Movimientos → Extractos (importación) → Conciliación → Reporte')) | Out-Null
$docParts.Add((PageBreak)) | Out-Null
# Cierre
$docParts.Add((H1 'Siguiente Paso')) | Out-Null
$docParts.Add((Bullet 'Demostración guiada con escenarios reales del cliente.')) | Out-Null
$docParts.Add((Bullet 'Validación de alcance y parametrización inicial.')) | Out-Null
$docParts.Add((Bullet 'Plan de implementación (migración, capacitación, puesta en marcha).')) | Out-Null
$documentXml = @"
$($docParts -join "")
"@
$contentTypes = @"
"@
$rels = @"
"@
$docRels = @"
"@
$created = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
$core = @"
Presentación Comercial – Sistema ERP
ERP
ERP
$created
$created
"@
$app = @"
ERP
"@
$tmpRoot = Join-Path $baseDir 'tools\._tmp_docx_presentacion'
if (Test-Path $tmpRoot) { Remove-Item -Recurse -Force $tmpRoot }
New-Item -ItemType Directory -Force -Path (Join-Path $tmpRoot '_rels') | Out-Null
New-Item -ItemType Directory -Force -Path (Join-Path $tmpRoot 'word\_rels') | Out-Null
New-Item -ItemType Directory -Force -Path (Join-Path $tmpRoot 'docProps') | Out-Null
$utf8NoBom = New-Object System.Text.UTF8Encoding($false)
[System.IO.File]::WriteAllText((Join-Path $tmpRoot '[Content_Types].xml'), $contentTypes, $utf8NoBom)
[System.IO.File]::WriteAllText((Join-Path $tmpRoot '_rels\.rels'), $rels, $utf8NoBom)
[System.IO.File]::WriteAllText((Join-Path $tmpRoot 'word\document.xml'), $documentXml, $utf8NoBom)
[System.IO.File]::WriteAllText((Join-Path $tmpRoot 'word\_rels\document.xml.rels'), $docRels, $utf8NoBom)
[System.IO.File]::WriteAllText((Join-Path $tmpRoot 'docProps\core.xml'), $core, $utf8NoBom)
[System.IO.File]::WriteAllText((Join-Path $tmpRoot 'docProps\app.xml'), $app, $utf8NoBom)
Add-Type -AssemblyName System.IO.Compression.FileSystem
if (Test-Path $outFile) { Remove-Item -Force $outFile }
[System.IO.Compression.ZipFile]::CreateFromDirectory($tmpRoot, $outFile)
Remove-Item -Recurse -Force $tmpRoot
Write-Host "OK: DOCX generado en: $outFile"