diff --git a/App_Code/ClsGenerales.vb b/App_Code/ClsGenerales.vb
index 5ce060b9a..37a62c152 100644
--- a/App_Code/ClsGenerales.vb
+++ b/App_Code/ClsGenerales.vb
@@ -399,15 +399,43 @@ Public Class ClsGenerales
Try
SqlAdapter.Fill(DSet)
- DSet.Tables(0).TableName = "Indicadores"
- DSet.Tables(1).TableName = "DetalleDia"
- DSet.Tables(2).TableName = "DetalleAnualesMes"
- DSet.Tables(3).TableName = "VentasPorVendedor"
- DSet.Tables(4).TableName = "VentasPorClasificacion"
- DSet.Tables(5).TableName = "VentasPorMarca"
- DSet.Tables(6).TableName = "VentasPorPS"
- DSet.Tables(7).TableName = "VentasPorCliente"
- DSet.Tables(8).TableName = "VentasPorProveedor"
+ If DSet.Tables.Count > 0 Then
+ Select Case Opcion
+ Case 1 ' Cuentas por Cobrar
+ DSet.Tables(0).TableName = "Indicadores"
+ If DSet.Tables.Count > 1 Then DSet.Tables(1).TableName = "DetalleDia"
+ If DSet.Tables.Count > 2 Then DSet.Tables(2).TableName = "DetalleAnualesMes"
+ If DSet.Tables.Count > 3 Then DSet.Tables(3).TableName = "VentasPorVendedor"
+ If DSet.Tables.Count > 4 Then DSet.Tables(4).TableName = "VentasPorClasificacion"
+ If DSet.Tables.Count > 5 Then DSet.Tables(5).TableName = "VentasPorMarca"
+ If DSet.Tables.Count > 6 Then DSet.Tables(6).TableName = "VentasPorPS"
+ If DSet.Tables.Count > 7 Then DSet.Tables(7).TableName = "VentasPorCliente"
+ If DSet.Tables.Count > 8 Then DSet.Tables(8).TableName = "VentasPorProveedor"
+
+ Case 2 ' Recuperación
+ DSet.Tables(0).TableName = "CarteraPorSubproyecto"
+ If DSet.Tables.Count > 1 Then DSet.Tables(1).TableName = "CarteraPorVendedor"
+ If DSet.Tables.Count > 2 Then DSet.Tables(2).TableName = "RecuperacionPorSubproyecto"
+ If DSet.Tables.Count > 3 Then DSet.Tables(3).TableName = "RecuperacionPorVendedor"
+ If DSet.Tables.Count > 4 Then DSet.Tables(4).TableName = "RecuperacionPorCliente"
+ If DSet.Tables.Count > 5 Then DSet.Tables(5).TableName = "CxCMensual"
+
+
+ Case 3 'Compras
+ If DSet.Tables.Count > 1 Then DSet.Tables(1).TableName = "ComprasPorClasificación"
+ If DSet.Tables.Count > 2 Then DSet.Tables(2).TableName = "ComprasPorMarca"
+ If DSet.Tables.Count > 3 Then DSet.Tables(3).TableName = "ComprasPorPS"
+ If DSet.Tables.Count > 4 Then DSet.Tables(4).TableName = "ComprasPorProveedor"
+
+ Case 4 'Cuentas Por Pagar
+ DSet.Tables(0).TableName = "CxPPorSubproyecto"
+ If DSet.Tables.Count > 1 Then DSet.Tables(1).TableName = "CxPPorProveedor"
+ If DSet.Tables.Count > 2 Then DSet.Tables(2).TableName = "PagosPorSubproyecto"
+ If DSet.Tables.Count > 3 Then DSet.Tables(3).TableName = "PagosPorProveedor"
+ If DSet.Tables.Count > 4 Then DSet.Tables(4).TableName = "CxPMensual"
+ End Select
+ End If
+
Catch ex As Exception
' Manejo de errores
@@ -720,55 +748,55 @@ Public Class ClsGenerales
End Try
Return Retorno
- End Function
-
+ End Function
+
#End Region
-
- '#Region " E S T A D O S"
- ' Public Function GetGralEstados() As Boolean
- ' Dim Retorno As Boolean = False
- ' DataAdapter("PA_Gral_EstadoGet")
- ' Try
- ' SqlAdapter.Fill(Data)
- ' Retorno = True
- ' Catch ex As Exception
- ' OnError("Ocurrió un error al obtener el Catálogo de Estados.", ex, SqlAdapter.SelectCommand.Parameters.ParametrosInfo())
- ' End Try
-
- ' Return Retorno
- ' End Function
- '#End Region
-
- '#Region " M U N I C I P I O S"
- ' Public Function GetGralMunicipios() As Boolean
- ' Dim Retorno As Boolean = False
- ' DataAdapter("PA_Gral_MunicipioGet")
- ' Try
- ' SqlAdapter.Fill(Data)
- ' Retorno = True
- ' Catch ex As Exception
- ' OnError("Ocurrió un error al obtener el Catálogo de Municipios.", ex, SqlAdapter.SelectCommand.Parameters.ParametrosInfo())
- ' End Try
-
- ' Return Retorno
- ' End Function
- '#End Region
-
- '#Region " P A I S E S"
- ' Public Function GetGralPaises() As Boolean
- ' Dim Retorno As Boolean = False
- ' DataAdapter("PA_Gral_PaisGet")
- ' Try
- ' SqlAdapter.Fill(Data)
- ' Retorno = True
- ' Catch ex As Exception
- ' OnError("Ocurrió un error al obtener el Catálogo de Paises.", ex, SqlAdapter.SelectCommand.Parameters.ParametrosInfo())
- ' End Try
-
- ' Return Retorno
- ' End Function
- '#End Region
-
+
+ '#Region " E S T A D O S"
+ ' Public Function GetGralEstados() As Boolean
+ ' Dim Retorno As Boolean = False
+ ' DataAdapter("PA_Gral_EstadoGet")
+ ' Try
+ ' SqlAdapter.Fill(Data)
+ ' Retorno = True
+ ' Catch ex As Exception
+ ' OnError("Ocurrió un error al obtener el Catálogo de Estados.", ex, SqlAdapter.SelectCommand.Parameters.ParametrosInfo())
+ ' End Try
+
+ ' Return Retorno
+ ' End Function
+ '#End Region
+
+ '#Region " M U N I C I P I O S"
+ ' Public Function GetGralMunicipios() As Boolean
+ ' Dim Retorno As Boolean = False
+ ' DataAdapter("PA_Gral_MunicipioGet")
+ ' Try
+ ' SqlAdapter.Fill(Data)
+ ' Retorno = True
+ ' Catch ex As Exception
+ ' OnError("Ocurrió un error al obtener el Catálogo de Municipios.", ex, SqlAdapter.SelectCommand.Parameters.ParametrosInfo())
+ ' End Try
+
+ ' Return Retorno
+ ' End Function
+ '#End Region
+
+ '#Region " P A I S E S"
+ ' Public Function GetGralPaises() As Boolean
+ ' Dim Retorno As Boolean = False
+ ' DataAdapter("PA_Gral_PaisGet")
+ ' Try
+ ' SqlAdapter.Fill(Data)
+ ' Retorno = True
+ ' Catch ex As Exception
+ ' OnError("Ocurrió un error al obtener el Catálogo de Paises.", ex, SqlAdapter.SelectCommand.Parameters.ParametrosInfo())
+ ' End Try
+
+ ' Return Retorno
+ ' End Function
+ '#End Region
+
#Region " P O B L A C I O N E S"
Public Function GetGralPoblaciones() As Boolean
Dim Retorno As Boolean = False
diff --git a/App_Code/ClsVentas.vb b/App_Code/ClsVentas.vb
index 8b83de472..f6abba49c 100644
--- a/App_Code/ClsVentas.vb
+++ b/App_Code/ClsVentas.vb
@@ -7728,7 +7728,7 @@ Public Class ClsVentas
End Function
- Public Function GetSMSIndicadores(Opcion As Integer, FechaInicio As Date, FechaFin As Date, CveUsuario As Integer, CveVendedor As Integer, CveGerenteVendedor As Integer, CveUsuarioTecnico As Integer, CveEmpresa As Integer) As Boolean
+ Public Function GetSMSIndicadores(Opcion As Integer, FechaInicio As Date, FechaFin As Date, CveUsuario As Integer, CveVendedor As Integer, CveUsuarioTecnico As Integer, CveEmpresa As Integer) As Boolean
Dim Retorno As Boolean = False
DataAdapter("PA_SMS_IndicadoresGet")
With SqlAdapter.SelectCommand.Parameters
@@ -7737,7 +7737,6 @@ Public Class ClsVentas
.Add("@FechaFin", SqlDbType.Date).Value = FechaFin
.Add("@CveUsuario", SqlDbType.Int).Value = CveUsuario
.Add("@CveVendedor", SqlDbType.Int).Value = CveVendedor
- .Add("@CveGerenteVendedor", SqlDbType.Int).Value = CveGerenteVendedor
.Add("@CveUsuarioTecnico", SqlDbType.Int).Value = CveUsuarioTecnico
.Add("@CveEmpresa", SqlDbType.Int).Value = CveEmpresa
End With
diff --git a/Contabilidad/RepAnexoCatalogoCC.aspx b/Contabilidad/RepAnexoCatalogoCC.aspx
index 0e105651a..d05a8aad4 100644
--- a/Contabilidad/RepAnexoCatalogoCC.aspx
+++ b/Contabilidad/RepAnexoCatalogoCC.aspx
@@ -574,7 +574,7 @@
@@ -1289,6 +1866,166 @@
}
+ function generarGraficaSucursales() {
+ // 1) Obtener la tabla completa
+ var $grid = $('table[id$="gvResumenSucursales"]');
+
+ // 2) Buscar TODOS los checkbox marcados
+ var $checks = $grid.find('input.header-checkbox:checked');
+ if ($checks.length === 0) {
+ alert('Por favor, seleccione al menos una columna para graficar.');
+ return false;
+ }
+
+ // 3) Filas de datos: todas las
que tengan
+ var $dataRows = $grid.find('tr').has('td');
+
+ // 4) Categorías = texto de la primera celda (Sucursal)
+ var categorias = $dataRows.map(function () {
+ return $(this).find('td').eq(0).text().trim();
+ }).get();
+
+ // 5) Localizar tus subheaders (segunda fila de encabezado)
+ var $headerRows = $grid.find('tr').filter(function () {
+ return $(this).find('th').length > 1;
+ });
+ var $subThs = $headerRows.eq(1).find('th'); // esos 4
+
+ // 6) Construir las series
+ var series = $checks.map(function () {
+ var $chk = $(this);
+ var $th = $chk.closest('th');
+ // idxSub = posición dentro de los 4 subheaders (0..3)
+ var idxSub = $subThs.index($th);
+ // +1 porque la columna 0 es "Sucursal"
+ var colIndex = idxSub + 1;
+ // Leer data-field (VentaAnual, UtilidadAnual, etc.) y formatear nombre
+ var field = $chk.data('field');
+ var name = field.replace(/([a-z])([A-Z])/g, '$1 $2');
+ // Mapear los valores de cada fila para esta columna
+ var data = $dataRows.map(function () {
+ var txt = $(this).find('td').eq(colIndex).text().replace(/,/g, '');
+ return parseFloat(txt) || 0;
+ }).get();
+ return { name: name, data: data };
+ }).get();
+
+ // 7) Dibujar Highcharts
+ Highcharts.chart('chartContainer', {
+ chart: { type: 'line' },
+ title: { text: 'Comparativo por Sucursal' },
+ xAxis: {
+ categories: categorias,
+ title: { text: 'Sucursal' }
+ },
+ yAxis: {
+ title: { text: 'Monto' },
+ labels: {
+ formatter: function () {
+ return '$' + Highcharts.numberFormat(this.value, 0);
+ }
+ }
+ },
+ tooltip: {
+ headerFormat: '{series.name} ',
+ pointFormat: 'Sucursal: {point.category} Valor: ${point.y:,.2f}'
+ },
+ plotOptions: {
+ series: { marker: { enabled: true } }
+ },
+ series: series
+ });
+
+ // 8) Mostrar el modal
+ $('#DivModalGrafica').modal('show');
+ return false;
+ }
+
+ function generarGrafica(gridId) {
+ var $grid = $('#' + gridId);
+
+ // Encuentra las filas de encabezado (donde están los checkboxes)
+ var $headerRows = $grid.find('tr:has(th)');
+ var $subHeader = $headerRows.length > 1 ? $headerRows.eq(1) : $headerRows.eq(0);
+ var $subThs = $subHeader.find('th');
+
+ // Buscar checkboxes marcados
+ var $checks = $grid.find('input.header-checkbox:checked');
+ if ($checks.length === 0) {
+ alert('Por favor, seleccione al menos una columna para graficar.');
+ return false;
+ }
+
+ // Filas de datos
+ var $dataRows = $grid.find('tr').has('td');
+
+ // Categorías (eje X)
+ var categorias = $dataRows.map(function () {
+ return $(this).find('td').eq(0).text().trim();
+ }).get();
+
+ // Construir series
+ var series = [];
+ $checks.each(function () {
+ var $chk = $(this);
+ var field = $chk.data('field');
+
+ // Buscar el índice de la columna que tiene ese data-field
+ var colIndex = -1;
+ $subThs.each(function (i) {
+ var $input = $(this).find('input.header-checkbox');
+ if ($input.length && $input.data('field') === field) {
+ colIndex = i + 1; // +1 porque la primera columna es la de las categorías
+ }
+ });
+
+ if (colIndex === -1) return; // No encontrado, saltar
+
+ var name = field.replace(/([a-z])([A-Z])/g, '$1 $2');
+ var data = $dataRows.map(function () {
+ var txt = $(this).find('td').eq(colIndex).text().replace(/,/g, '');
+ return parseFloat(txt) || 0;
+ }).get();
+
+ series.push({ name: name, data: data });
+ });
+
+ // Título dinámico
+ var titulo = $grid.closest('.portlet').find('.caption-subject').text();
+ var modalTitulo = document.getElementById('modalTitulo');
+ if (modalTitulo) modalTitulo.innerText = 'Comparativo: ' + titulo;
+
+ // Dibujar gráfica
+ Highcharts.chart('chartContainer', {
+ chart: { type: 'line' },
+ title: { text: titulo }, // Usar el título dinámico
+ xAxis: {
+ categories: categorias,
+ title: { text: 'Categoría' } // Título genérico para el eje X
+ },
+ yAxis: {
+ title: { text: 'Monto (MXN)' },
+ labels: {
+ formatter: function () {
+ return '$' + Highcharts.numberFormat(this.value, 0);
+ }
+ }
+ },
+ tooltip: {
+ headerFormat: '{series.name} ',
+ pointFormat: 'Categoría: {point.category} Valor: ${point.y:,.2f}'
+ },
+ plotOptions: {
+ series: { marker: { enabled: true } }
+ },
+ series: series
+ });
+
+ $('#DivModalGrafica').modal('show');
+ return false;
+ }
+
+
diff --git a/General/Dashboard.aspx.vb b/General/Dashboard.aspx.vb
index 21ba073fa..5fe165fe6 100644
--- a/General/Dashboard.aspx.vb
+++ b/General/Dashboard.aspx.vb
@@ -25,8 +25,7 @@ Partial Class General_Dashboard
End Sub
Private Sub BindDropdown()
- ' Actualmente las opciones están definidas en el markup
- ' Aquí podrías cargar dinámicamente si lo deseas en el futuro
+
End Sub
Public Overrides Sub VerifyRenderingInServerForm(control As Control)
@@ -49,7 +48,7 @@ Partial Class General_Dashboard
Select Case opcion
Case 1 ' Ingresos
- ProcesarDatosIndicadores(ds.Tables("Indicadores"))
+ IndicadoresIngresos(ds.Tables("Indicadores"))
CargarResumenSucursales(ds.Tables("DetalleDia"))
CargarVentasMensuales(ds.Tables("DetalleAnualesMes"))
@@ -63,79 +62,88 @@ Partial Class General_Dashboard
Case 2 ' Recuperación
- ' TODO: Implementar carga de indicadores, gráficas y grids para Recuperación
+ IndicadoresRecuperacionCxc(ds.Tables("CarteraPorSubproyecto"), ds.Tables("RecuperacionPorSubproyecto"))
+
+ CargarCarteraPorSucursal(ds.Tables("CarteraPorSubproyecto"))
+ CargarCarteraPorVendedor(ds.Tables("CarteraPorVendedor"))
+ CargarRecuperacionPorSucursal(ds.Tables("RecuperacionPorSubproyecto"))
+ CargarRecuperacionPorCliente(ds.Tables("RecuperacionPorCliente"))
+ CargarCxCMensual(ds.Tables("CxCMensual"))
Case 3 ' Compras
- ' TODO: Implementar carga para Compras
+ CargarComprasPorClasificacion(ds.Tables("ComprasPorClasificación"))
+ CargarComprasPorMarca(ds.Tables("ComprasPorMarca"))
+ CargarComprasPorPS(ds.Tables("ComprasPorPS"))
+ CargarComprasPorProveedor(ds.Tables("ComprasPorProveedor"))
- Case 4 ' Gasto
- ' TODO: Implementar carga para Gasto
+ Case 4 ' Cuentas por Pagar
+ IndicadoresCxP(ds.Tables("CxPPorSubproyecto"), ds.Tables("PagosPorSubproyecto"))
- Case 5 ' Cuentas por Pagar
- ' TODO: Implementar carga para CxP
+ ' Cargar GridViews
+ CargarCxPPorSucursal(ds.Tables("CxPPorSubproyecto"))
+ CargarCxPPorProveedor(ds.Tables("CxPPorProveedor"))
+ CargarPagosPorSucursal(ds.Tables("PagosPorSubproyecto"))
+ CargarPagosPorProveedor(ds.Tables("PagosPorProveedor"))
+ CargarCxPMensual(ds.Tables("CxPMensual"))
- Case 6 ' Inventario
+ Case 5 ' Inventario
' TODO: Implementar carga para Inventario
- Case 7 ' Utilidad
+ Case 6 ' Utilidad
' TODO: Implementar carga para Utilidad
- Case 8 ' Impuestos
+ Case 7 ' Impuestos
' TODO: Implementar carga para Impuestos
- Case 9 ' CRM
+ Case 8 ' CRM
' TODO: Implementar carga para CRM
- Case 10 ' RH
+ Case 9 ' RH
' TODO: Implementar carga para RH
- Case 11 ' AF
+ Case 10 ' AF
' TODO: Implementar carga para AF
End Select
End Sub
Protected Sub LnkExportarPDF_Click(sender As Object, e As EventArgs) Handles LnkExportarPDF.Click
- DivIndicadoresLeft.InnerHtml &= DivIndicadoresRight.InnerHtml
- DivIndicadoresRight.InnerHtml = String.Empty
+ DivIndicadoresIngresosLeft.InnerHtml &= DivIndicadoresIngresosRight.InnerHtml
+ DivIndicadoresIngresosRight.InnerHtml = String.Empty
pnlDashboard.GenerarReportePDF("Reporte Resumen de Indicadores")
End Sub
-
- Private Sub CargarIndicadores(dt As DataTable)
- If dt IsNot Nothing AndAlso dt.Rows.Count > 0 Then
- ProcesarDatosIndicadores(dt)
- End If
- End Sub
-
- Private Sub ProcesarDatosIndicadores(dt As DataTable)
+ Private Sub IndicadoresIngresos(dt As DataTable)
If dt Is Nothing OrElse dt.Rows.Count = 0 Then
Return
End If
Dim dr As DataRow = dt.Rows(0)
- ' Indicador Año
- MuestraIndicador(DivIndicadoresLeft, "blue", "fa fa-calendar", "Año Actual", dr("AcumAño").ToString.FormatoNumero(0), "#", "Acumulado",
+ DivIndicadoresIngresosLeft.InnerHtml = String.Empty
+ DivIndicadoresIngresosRight.InnerHtml = String.Empty
+
+ ' Indicador Año
+ MuestraIndicador(DivIndicadoresIngresosLeft, "blue", "fa fa-calendar", "Año Actual", dr("AcumAño").ToString.FormatoNumero(0), "#", "Acumulado",
dr("AcumAñoPromedio").ToString.FormatoNumero(0), "#", "Ticket Promedio",
dr("AcumAñoContado").ToString.FormatoNumero(0), "#", "Contado",
dr("AcumAñoCredito").ToString.FormatoNumero(0), "#", "Crédito")
- ' Indicador Mes
- MuestraIndicador(DivIndicadoresLeft, "green", "fa fa-calendar-check-o", "Mes Actual",
+ ' Indicador Mes
+ MuestraIndicador(DivIndicadoresIngresosLeft, "green", "fa fa-calendar-check-o", "Mes Actual",
dr("AcumMes").ToString.FormatoNumero(0), "#", "Acumulado",
dr("AcumMesPromedio").ToString.FormatoNumero(0), "#", "Ticket Promedio",
dr("AcumMesContado").ToString.FormatoNumero(0), "#", "Contado",
dr("AcumMesCredito").ToString.FormatoNumero(0), "#", "Crédito")
- ' Indicador Semana
- MuestraIndicador(DivIndicadoresRight, "purple", "fa fa-calendar-minus-o", "Semana Actual",
+ ' Indicador Semana
+ MuestraIndicador(DivIndicadoresIngresosRight, "purple", "fa fa-calendar-minus-o", "Semana Actual",
dr("AcumSemana").ToString.FormatoNumero(0), "#", "Acumulado",
dr("AcumSemanaPromedio").ToString.FormatoNumero(0), "#", "Ticket Promedio",
dr("AcumSemanaContado").ToString.FormatoNumero(0), "#", "Contado",
dr("AcumSemanaCredito").ToString.FormatoNumero(0), "#", "Crédito")
- MuestraIndicador(DivIndicadoresRight, "red", "fa fa-sun-o", "Hoy",
+ MuestraIndicador(DivIndicadoresIngresosRight, "red", "fa fa-sun-o", "Hoy",
"0".FormatoNumero(0), "#", "Acumulado",
"0".FormatoNumero(0), "#", "Ticket Promedio",
"0".FormatoNumero(0), "#", "Contado",
@@ -143,6 +151,133 @@ Partial Class General_Dashboard
End Sub
+ Private Sub IndicadoresRecuperacionCxc(dtCartera As DataTable, dtRecuperacion As DataTable)
+ If dtCartera Is Nothing OrElse dtCartera.Rows.Count = 0 Then Return
+ If dtRecuperacion Is Nothing OrElse dtRecuperacion.Rows.Count = 0 Then Return
+
+ ' Calcular totales para Cartera Vencida
+ Dim totalVencido As Decimal = 0
+ Dim totalPorVencer As Decimal = 0
+ Dim totalCxC As Decimal = 0
+ Dim maxRotacion As Decimal = 0
+
+ For Each row As DataRow In dtCartera.Rows
+ totalVencido += If(IsDBNull(row("Vencido")), 0D, row("Vencido")).ToString.ToDecimal()
+ totalPorVencer += If(IsDBNull(row("Por Vencer")), 0D, row("Por Vencer")).ToString.ToDecimal()
+ If dtCartera.Columns.Contains("RotacionCartera") AndAlso Not IsDBNull(row("RotacionCartera")) Then
+ Dim rotacion = Convert.ToDecimal(row("RotacionCartera"))
+ If rotacion > maxRotacion Then maxRotacion = rotacion
+ End If
+
+ Next
+
+ totalCxC = totalVencido + totalPorVencer
+
+ ' Calcular total para Recuperación
+ Dim totalRecuperado As Decimal = 0
+ For Each row As DataRow In dtRecuperacion.Rows
+ totalRecuperado += If(IsDBNull(row("Recuperado")), 0D, row("Recuperado")).ToString.ToDecimal()
+ Next
+
+ DivIndicadoresRecuperacionLeft.InnerHtml = ""
+ DivIndicadoresRecuperacionRight.InnerHtml = ""
+
+ ' Indicador Cartera Vencida
+ MuestraIndicador(DivIndicadoresRecuperacionLeft, "blue", "fa fa-calendar", "Cartera Vencida",
+ totalCxC.ToString.FormatoNumero(0), "#", "CxC",
+ totalVencido.ToString.FormatoNumero(0), "#", "Vencido",
+ totalPorVencer.ToString.FormatoNumero(0), "#", "Por Vencer")
+
+ 'Indicador KPI Recuperación
+ MuestraIndicadorKPI(DivIndicadoresRecuperacionLeft, "purple", "fa fa-usd",
+ "Recuperación",
+ totalRecuperado.ToString.FormatoNumero(0),
+ "#",
+ "Recuperación")
+
+ Dim factorRecuperacion As Decimal = 0
+ If totalCxC > 0 Then
+ factorRecuperacion = (totalRecuperado / totalCxC)
+ End If
+
+ MuestraIndicadorKPI(DivIndicadoresRecuperacionRight, "green", "fa fa-fa-percent",
+ "Factor Recuperación",
+ factorRecuperacion.ToString("N2") & "%",
+ "#",
+ "Porcentaje de cartera recuperada")
+
+ MuestraIndicadorKPI(DivIndicadoresRecuperacionRight, "red", "fa fa-refresh",
+ "Rotación Cartera",
+ maxRotacion.ToString("N1"),
+ "#",
+ "Máxima rotación de cartera entre sucursales")
+
+ End Sub
+
+ Private Sub IndicadoresCxP(dtCxP As DataTable, dtPagos As DataTable)
+ If dtCxP Is Nothing OrElse dtCxP.Rows.Count = 0 Then Return
+ If dtPagos Is Nothing OrElse dtPagos.Rows.Count = 0 Then Return
+
+ ' Calcular totales para CxP
+ Dim totalVencido As Decimal = 0
+ Dim totalPorVencer As Decimal = 0
+ Dim totalCxP As Decimal = 0
+ Dim maxRotacion As Decimal = 0
+
+ For Each row As DataRow In dtCxP.Rows
+ totalVencido += Convert.ToDecimal(If(IsDBNull(row("Vencido")), 0D, row("Vencido")))
+ totalPorVencer += Convert.ToDecimal(If(IsDBNull(row("Por Vencer")), 0D, row("Por Vencer")))
+
+ ' Obtener rotación máxima
+ If dtCxP.Columns.Contains("RotacionCartera") AndAlso Not IsDBNull(row("RotacionCartera")) Then
+ Dim rotacion = Convert.ToDecimal(row("RotacionCartera"))
+ If rotacion > maxRotacion Then maxRotacion = rotacion
+ End If
+ Next
+ totalCxP = totalVencido + totalPorVencer
+
+ ' Calcular total pagado
+ Dim totalPagado As Decimal = 0
+ For Each row As DataRow In dtPagos.Rows
+ totalPagado += Convert.ToDecimal(If(IsDBNull(row("Recuperado")), 0D, row("Recuperado")))
+ Next
+
+ DivIndicadoresCxPLeft.InnerHtml = ""
+ DivIndicadoresRecuperacionRight.InnerHtml = ""
+
+ ' Indicador CxP
+ MuestraIndicador(DivIndicadoresCxPLeft, "blue", "fa fa-calendar", "Cuentas por Pagar",
+ totalCxP.ToString.FormatoNumero(0), "#", "Total CxP",
+ totalVencido.ToString.FormatoNumero(0), "#", "Vencido",
+ totalPorVencer.ToString.FormatoNumero(0), "#", "Por Vencer")
+
+ ' KPI Pagado
+ MuestraIndicadorKPI(DivIndicadoresCxPLeft, "purple", "fa fa-usd",
+ "Total Pagado",
+ totalPagado.ToString.FormatoNumero(0),
+ "#",
+ "Total pagado a proveedores")
+
+ ' KPI Factor CxP vs Pagado
+ Dim factorPago As Decimal = 0
+ If totalCxP > 0 Then
+ factorPago = (totalPagado / totalCxP) * 100
+ End If
+
+ MuestraIndicadorKPI(DivIndicadoresCxPRight, "green", "fa fa-percent",
+ "Factor Pago",
+ factorPago.ToString("N2") & "%",
+ "#",
+ "Porcentaje de CxP pagado")
+
+ ' KPI Rotación de Cartera
+ MuestraIndicadorKPI(DivIndicadoresCxPRight, "red", "fa fa-refresh",
+ "Rotación CxP",
+ maxRotacion.ToString("N1") & " días",
+ "#",
+ "Máxima rotación de CxP entre sucursales")
+ End Sub
+
Private Sub CargarVentasMensuales(dt As DataTable)
If dt Is Nothing OrElse dt.Rows.Count = 0 Then
Return
@@ -238,50 +373,411 @@ Partial Class General_Dashboard
Protected Sub gvResumenSucursales_RowCreated(sender As Object, e As GridViewRowEventArgs)
If e.Row.RowType = DataControlRowType.Header Then
- ' Limpiar celdas originales
e.Row.Cells.Clear()
+ Dim grid As GridView = DirectCast(sender, GridView)
- ' Crear primera fila de encabezado (grupos)
- Dim headerRow As New GridViewRow(0, 0, DataControlRowType.Header, DataControlRowState.Normal)
+ ' --- Fila 1 ---
+ Dim headerRow1 As New GridViewRow(0, 0, DataControlRowType.Header, DataControlRowState.Normal)
- ' Celda para "Sucursal" (ocupa 2 filas)
Dim cellSucursal As New TableHeaderCell()
cellSucursal.RowSpan = 2
- cellSucursal.Text = "Sucursal"
- headerRow.Cells.Add(cellSucursal)
+ cellSucursal.VerticalAlign = VerticalAlign.Middle
+ cellSucursal.Controls.Add(New LiteralControl("Sucursal "))
+ Dim hypGrafica As New HyperLink()
+ hypGrafica.NavigateUrl = "javascript:void(0);"
+ hypGrafica.Attributes.Add("onclick", "return generarGraficaSucursales();")
+ hypGrafica.CssClass = "grafica-icon"
+ hypGrafica.Controls.Add(New LiteralControl(""))
+ cellSucursal.Controls.Add(hypGrafica)
+ headerRow1.Cells.Add(cellSucursal)
- ' Celda para "Año" (abarca 2 columnas)
- Dim cellAño As New TableHeaderCell()
- cellAño.ColumnSpan = 2
- cellAño.Text = "Año"
- headerRow.Cells.Add(cellAño)
+ Dim cellAnio As New TableHeaderCell()
+ cellAnio.ColumnSpan = 2
+ cellAnio.HorizontalAlign = HorizontalAlign.Center
+ cellAnio.Text = "Año"
+ headerRow1.Cells.Add(cellAnio)
- ' Celda para "Mes" (abarca 2 columnas)
Dim cellMes As New TableHeaderCell()
cellMes.ColumnSpan = 2
+ cellMes.HorizontalAlign = HorizontalAlign.Center
cellMes.Text = "Mes"
- headerRow.Cells.Add(cellMes)
+ headerRow1.Cells.Add(cellMes)
- ' Añadir fila al GridView
- Dim grid As GridView = DirectCast(sender, GridView)
- grid.Controls(0).Controls.AddAt(0, headerRow)
+ headerRow1.TableSection = TableRowSection.TableHeader
+ grid.Controls(0).Controls.AddAt(0, headerRow1)
- ' Crear segunda fila de encabezado (subtítulos)
- Dim subHeaderRow As New GridViewRow(1, 0, DataControlRowType.Header, DataControlRowState.Normal)
-
- ' Subtítulos para "Año"
- subHeaderRow.Cells.Add(New TableHeaderCell() With {.Text = "Venta"})
- subHeaderRow.Cells.Add(New TableHeaderCell() With {.Text = "Utilidad"})
-
- ' Subtítulos para "Mes"
- subHeaderRow.Cells.Add(New TableHeaderCell() With {.Text = "Venta"})
- subHeaderRow.Cells.Add(New TableHeaderCell() With {.Text = "Utilidad"})
-
- grid.Controls(0).Controls.AddAt(1, subHeaderRow)
+ ' --- Fila 2 ---
+ Dim headerRow2 As New GridViewRow(1, 0, DataControlRowType.Header, DataControlRowState.Normal)
+ headerRow2.Cells.Add(CreateSubHeaderCell("Venta", "chkVentaAnual", "VentaAnual"))
+ headerRow2.Cells.Add(CreateSubHeaderCell("Utilidad", "chkUtilidadAnual", "UtilidadAnual"))
+ headerRow2.Cells.Add(CreateSubHeaderCell("Venta", "chkVentaMensual", "VentaMensual"))
+ headerRow2.Cells.Add(CreateSubHeaderCell("Utilidad", "chkUtilidadMensual", "UtilidadMensual"))
+ headerRow2.TableSection = TableRowSection.TableHeader
+ grid.Controls(0).Controls.AddAt(1, headerRow2)
End If
End Sub
+ Protected Sub gvVentasPorSucursal_RowCreated(sender As Object, e As GridViewRowEventArgs)
+ If e.Row.RowType = DataControlRowType.Header Then
+ e.Row.Cells.Clear()
+ Dim grid As GridView = DirectCast(sender, GridView)
+
+ ' --- Fila 1 ---
+ Dim headerRow1 As New GridViewRow(0, 0, DataControlRowType.Header, DataControlRowState.Normal)
+
+ ' Celda principal (Sucursal)
+ Dim cellSucursal As New TableHeaderCell()
+ cellSucursal.RowSpan = 2
+ cellSucursal.VerticalAlign = VerticalAlign.Middle
+ cellSucursal.Controls.Add(New LiteralControl("Sucursal "))
+ Dim hypGrafica As New HyperLink()
+ hypGrafica.NavigateUrl = "javascript:void(0);"
+ hypGrafica.Attributes.Add("onclick", "return generarGrafica('" & grid.ClientID & "');")
+ hypGrafica.CssClass = "grafica-icon"
+ hypGrafica.Controls.Add(New LiteralControl(""))
+ cellSucursal.Controls.Add(hypGrafica)
+ headerRow1.Cells.Add(cellSucursal)
+
+ headerRow1.TableSection = TableRowSection.TableHeader
+ grid.Controls(0).Controls.AddAt(0, headerRow1)
+
+ ' --- Fila 2 (Subheaders) ---
+ Dim headerRow2 As New GridViewRow(1, 0, DataControlRowType.Header, DataControlRowState.Normal)
+
+ ' Subheaders con checkboxes
+ headerRow2.Cells.Add(CreateSubHeaderCell("Año", "chkAño", "Año"))
+ headerRow2.Cells.Add(CreateSubHeaderCell("Mes", "chkMes", "Mes"))
+ headerRow2.Cells.Add(CreateSubHeaderCell("Semana", "chkSemana", "Semana"))
+ headerRow2.Cells.Add(CreateSubHeaderCell("Día", "chkDia", "Dia"))
+
+ headerRow2.TableSection = TableRowSection.TableHeader
+ grid.Controls(0).Controls.AddAt(1, headerRow2)
+ End If
+ End Sub
+
+ Protected Sub gvVentasPorVendedor_RowCreated(sender As Object, e As GridViewRowEventArgs)
+ If e.Row.RowType = DataControlRowType.Header Then
+ e.Row.Cells.Clear()
+ Dim grid As GridView = DirectCast(sender, GridView)
+
+ ' --- Fila 1 ---
+ Dim headerRow1 As New GridViewRow(0, 0, DataControlRowType.Header, DataControlRowState.Normal)
+
+ ' Celda principal (Sucursal)
+ Dim cellSucursal As New TableHeaderCell()
+ cellSucursal.RowSpan = 2
+ cellSucursal.VerticalAlign = VerticalAlign.Middle
+ cellSucursal.Controls.Add(New LiteralControl("Vendedor "))
+ Dim hypGrafica As New HyperLink()
+ hypGrafica.NavigateUrl = "javascript:void(0);"
+ hypGrafica.Attributes.Add("onclick", "return generarGrafica('" & grid.ClientID & "');")
+ hypGrafica.CssClass = "grafica-icon"
+ hypGrafica.Controls.Add(New LiteralControl(""))
+ cellSucursal.Controls.Add(hypGrafica)
+ headerRow1.Cells.Add(cellSucursal)
+
+ headerRow1.TableSection = TableRowSection.TableHeader
+ grid.Controls(0).Controls.AddAt(0, headerRow1)
+
+ ' --- Fila 2 (Subheaders) ---
+ Dim headerRow2 As New GridViewRow(1, 0, DataControlRowType.Header, DataControlRowState.Normal)
+
+ ' Subheaders con checkboxes
+ headerRow2.Cells.Add(CreateSubHeaderCell("Año", "chkAño", "Año"))
+ headerRow2.Cells.Add(CreateSubHeaderCell("Mes", "chkMes", "Mes"))
+ headerRow2.Cells.Add(CreateSubHeaderCell("Semana", "chkSemana", "Semana"))
+ headerRow2.Cells.Add(CreateSubHeaderCell("Día", "chkDia", "Dia"))
+
+ headerRow2.TableSection = TableRowSection.TableHeader
+ grid.Controls(0).Controls.AddAt(1, headerRow2)
+ End If
+ End Sub
+
+ Protected Sub gvVentasPorClasificacion_RowCreated(sender As Object, e As GridViewRowEventArgs)
+ If e.Row.RowType = DataControlRowType.Header Then
+ e.Row.Cells.Clear()
+ Dim grid As GridView = DirectCast(sender, GridView)
+
+ ' --- Fila 1 ---
+ Dim headerRow1 As New GridViewRow(0, 0, DataControlRowType.Header, DataControlRowState.Normal)
+
+ ' Celda principal (Sucursal)
+ Dim cellSucursal As New TableHeaderCell()
+ cellSucursal.RowSpan = 2
+ cellSucursal.VerticalAlign = VerticalAlign.Middle
+ cellSucursal.Controls.Add(New LiteralControl("Clasificación "))
+ Dim hypGrafica As New HyperLink()
+ hypGrafica.NavigateUrl = "javascript:void(0);"
+ hypGrafica.Attributes.Add("onclick", "return generarGrafica('" & grid.ClientID & "');")
+ hypGrafica.CssClass = "grafica-icon"
+ hypGrafica.Controls.Add(New LiteralControl(""))
+ cellSucursal.Controls.Add(hypGrafica)
+ headerRow1.Cells.Add(cellSucursal)
+
+ headerRow1.TableSection = TableRowSection.TableHeader
+ grid.Controls(0).Controls.AddAt(0, headerRow1)
+
+ ' --- Fila 2 (Subheaders) ---
+ Dim headerRow2 As New GridViewRow(1, 0, DataControlRowType.Header, DataControlRowState.Normal)
+
+ ' Subheaders con checkboxes
+ headerRow2.Cells.Add(CreateSubHeaderCell("Año", "chkAño", "Año"))
+ headerRow2.Cells.Add(CreateSubHeaderCell("Mes", "chkMes", "Mes"))
+ headerRow2.Cells.Add(CreateSubHeaderCell("Semana", "chkSemana", "Semana"))
+ headerRow2.Cells.Add(CreateSubHeaderCell("Día", "chkDia", "Dia"))
+
+ headerRow2.TableSection = TableRowSection.TableHeader
+ grid.Controls(0).Controls.AddAt(1, headerRow2)
+ End If
+ End Sub
+
+ Protected Sub gvVentasPorMarca_RowCreated(sender As Object, e As GridViewRowEventArgs)
+ If e.Row.RowType = DataControlRowType.Header Then
+ e.Row.Cells.Clear()
+ Dim grid As GridView = DirectCast(sender, GridView)
+
+ ' --- Fila 1 ---
+ Dim headerRow1 As New GridViewRow(0, 0, DataControlRowType.Header, DataControlRowState.Normal)
+
+ ' Celda principal (Sucursal)
+ Dim cellSucursal As New TableHeaderCell()
+ cellSucursal.RowSpan = 2
+ cellSucursal.VerticalAlign = VerticalAlign.Middle
+ cellSucursal.Controls.Add(New LiteralControl("Marca "))
+ Dim hypGrafica As New HyperLink()
+ hypGrafica.NavigateUrl = "javascript:void(0);"
+ hypGrafica.Attributes.Add("onclick", "return generarGrafica('" & grid.ClientID & "');")
+ hypGrafica.CssClass = "grafica-icon"
+ hypGrafica.Controls.Add(New LiteralControl(""))
+ cellSucursal.Controls.Add(hypGrafica)
+ headerRow1.Cells.Add(cellSucursal)
+
+ headerRow1.TableSection = TableRowSection.TableHeader
+ grid.Controls(0).Controls.AddAt(0, headerRow1)
+
+ ' --- Fila 2 (Subheaders) ---
+ Dim headerRow2 As New GridViewRow(1, 0, DataControlRowType.Header, DataControlRowState.Normal)
+
+ ' Subheaders con checkboxes
+ headerRow2.Cells.Add(CreateSubHeaderCell("Año", "chkAño", "Año"))
+ headerRow2.Cells.Add(CreateSubHeaderCell("Mes", "chkMes", "Mes"))
+ headerRow2.Cells.Add(CreateSubHeaderCell("Semana", "chkSemana", "Semana"))
+ headerRow2.Cells.Add(CreateSubHeaderCell("Día", "chkDia", "Dia"))
+
+ headerRow2.TableSection = TableRowSection.TableHeader
+ grid.Controls(0).Controls.AddAt(1, headerRow2)
+ End If
+ End Sub
+
+ Protected Sub gvVentasPorPS_RowCreated(sender As Object, e As GridViewRowEventArgs)
+ If e.Row.RowType = DataControlRowType.Header Then
+ e.Row.Cells.Clear()
+ Dim grid As GridView = DirectCast(sender, GridView)
+
+ ' --- Fila 1 ---
+ Dim headerRow1 As New GridViewRow(0, 0, DataControlRowType.Header, DataControlRowState.Normal)
+
+ ' Celda principal (Sucursal)
+ Dim cellSucursal As New TableHeaderCell()
+ cellSucursal.RowSpan = 2
+ cellSucursal.VerticalAlign = VerticalAlign.Middle
+ cellSucursal.Controls.Add(New LiteralControl("PS "))
+ Dim hypGrafica As New HyperLink()
+ hypGrafica.NavigateUrl = "javascript:void(0);"
+ hypGrafica.Attributes.Add("onclick", "return generarGrafica('" & grid.ClientID & "');")
+ hypGrafica.CssClass = "grafica-icon"
+ hypGrafica.Controls.Add(New LiteralControl(""))
+ cellSucursal.Controls.Add(hypGrafica)
+ headerRow1.Cells.Add(cellSucursal)
+
+ headerRow1.TableSection = TableRowSection.TableHeader
+ grid.Controls(0).Controls.AddAt(0, headerRow1)
+
+ ' --- Fila 2 (Subheaders) ---
+ Dim headerRow2 As New GridViewRow(1, 0, DataControlRowType.Header, DataControlRowState.Normal)
+
+ ' Subheaders con checkboxes
+ headerRow2.Cells.Add(CreateSubHeaderCell("Año", "chkAño", "Año"))
+ headerRow2.Cells.Add(CreateSubHeaderCell("Mes", "chkMes", "Mes"))
+ headerRow2.Cells.Add(CreateSubHeaderCell("Semana", "chkSemana", "Semana"))
+ headerRow2.Cells.Add(CreateSubHeaderCell("Día", "chkDia", "Dia"))
+
+ headerRow2.TableSection = TableRowSection.TableHeader
+ grid.Controls(0).Controls.AddAt(1, headerRow2)
+ End If
+ End Sub
+
+ Protected Sub gvVentasPorCliente_RowCreated(sender As Object, e As GridViewRowEventArgs)
+ If e.Row.RowType = DataControlRowType.Header Then
+ e.Row.Cells.Clear()
+ Dim grid As GridView = DirectCast(sender, GridView)
+
+ ' --- Fila 1 ---
+ Dim headerRow1 As New GridViewRow(0, 0, DataControlRowType.Header, DataControlRowState.Normal)
+
+ ' Celda principal (Sucursal)
+ Dim cellSucursal As New TableHeaderCell()
+ cellSucursal.RowSpan = 2
+ cellSucursal.VerticalAlign = VerticalAlign.Middle
+ cellSucursal.Controls.Add(New LiteralControl("Cliente "))
+ Dim hypGrafica As New HyperLink()
+ hypGrafica.NavigateUrl = "javascript:void(0);"
+ hypGrafica.Attributes.Add("onclick", "return generarGrafica('" & grid.ClientID & "');")
+ hypGrafica.CssClass = "grafica-icon"
+ hypGrafica.Controls.Add(New LiteralControl(""))
+ cellSucursal.Controls.Add(hypGrafica)
+ headerRow1.Cells.Add(cellSucursal)
+
+ headerRow1.TableSection = TableRowSection.TableHeader
+ grid.Controls(0).Controls.AddAt(0, headerRow1)
+
+ ' --- Fila 2 (Subheaders) ---
+ Dim headerRow2 As New GridViewRow(1, 0, DataControlRowType.Header, DataControlRowState.Normal)
+
+ ' Subheaders con checkboxes
+ headerRow2.Cells.Add(CreateSubHeaderCell("Año", "chkAño", "Año"))
+ headerRow2.Cells.Add(CreateSubHeaderCell("Mes", "chkMes", "Mes"))
+ headerRow2.Cells.Add(CreateSubHeaderCell("Semana", "chkSemana", "Semana"))
+ headerRow2.Cells.Add(CreateSubHeaderCell("Día", "chkDia", "Dia"))
+
+ headerRow2.TableSection = TableRowSection.TableHeader
+ grid.Controls(0).Controls.AddAt(1, headerRow2)
+ End If
+ End Sub
+
+ Protected Sub gvVentasPorProveedor_RowCreated(sender As Object, e As GridViewRowEventArgs)
+ If e.Row.RowType = DataControlRowType.Header Then
+ e.Row.Cells.Clear()
+ Dim grid As GridView = DirectCast(sender, GridView)
+
+ ' --- Fila 1 ---
+ Dim headerRow1 As New GridViewRow(0, 0, DataControlRowType.Header, DataControlRowState.Normal)
+
+ ' Celda principal (Sucursal)
+ Dim cellSucursal As New TableHeaderCell()
+ cellSucursal.RowSpan = 2
+ cellSucursal.VerticalAlign = VerticalAlign.Middle
+ cellSucursal.Controls.Add(New LiteralControl("Proveedor "))
+ Dim hypGrafica As New HyperLink()
+ hypGrafica.NavigateUrl = "javascript:void(0);"
+ hypGrafica.Attributes.Add("onclick", "return generarGrafica('" & grid.ClientID & "');")
+ hypGrafica.CssClass = "grafica-icon"
+ hypGrafica.Controls.Add(New LiteralControl(""))
+ cellSucursal.Controls.Add(hypGrafica)
+ headerRow1.Cells.Add(cellSucursal)
+
+ headerRow1.TableSection = TableRowSection.TableHeader
+ grid.Controls(0).Controls.AddAt(0, headerRow1)
+
+ ' --- Fila 2 (Subheaders) ---
+ Dim headerRow2 As New GridViewRow(1, 0, DataControlRowType.Header, DataControlRowState.Normal)
+
+ ' Subheaders con checkboxes
+ headerRow2.Cells.Add(CreateSubHeaderCell("Año", "chkAño", "Año"))
+ headerRow2.Cells.Add(CreateSubHeaderCell("Mes", "chkMes", "Mes"))
+ headerRow2.Cells.Add(CreateSubHeaderCell("Semana", "chkSemana", "Semana"))
+ headerRow2.Cells.Add(CreateSubHeaderCell("Día", "chkDia", "Dia"))
+
+ headerRow2.TableSection = TableRowSection.TableHeader
+ grid.Controls(0).Controls.AddAt(1, headerRow2)
+ End If
+ End Sub
+
+ Protected Sub gvCarteraPorSucursal_RowCreated(sender As Object, e As GridViewRowEventArgs)
+ If e.Row.RowType = DataControlRowType.Header Then
+ e.Row.Cells.Clear()
+ Dim grid As GridView = DirectCast(sender, GridView)
+
+ ' --- Fila 1 ---
+ Dim headerRow1 As New GridViewRow(0, 0, DataControlRowType.Header, DataControlRowState.Normal)
+
+ ' Celda principal (Sucursal)
+ Dim cellSucursal As New TableHeaderCell()
+ cellSucursal.RowSpan = 2
+ cellSucursal.VerticalAlign = VerticalAlign.Middle
+ cellSucursal.Controls.Add(New LiteralControl("Sucursal "))
+ Dim hypGrafica As New HyperLink()
+ hypGrafica.NavigateUrl = "javascript:void(0);"
+ hypGrafica.Attributes.Add("onclick", "return generarGrafica('" & grid.ClientID & "');")
+ hypGrafica.CssClass = "grafica-icon"
+ hypGrafica.Controls.Add(New LiteralControl(""))
+ cellSucursal.Controls.Add(hypGrafica)
+ headerRow1.Cells.Add(cellSucursal)
+
+ headerRow1.TableSection = TableRowSection.TableHeader
+ grid.Controls(0).Controls.AddAt(0, headerRow1)
+
+ ' --- Fila 2 (Subheaders) ---
+ Dim headerRow2 As New GridViewRow(1, 0, DataControlRowType.Header, DataControlRowState.Normal)
+
+ ' Subheaders con checkboxes
+ headerRow2.Cells.Add(CreateSubHeaderCell("TotalCxC", "chkTotalCxC", "Total CxC"))
+ headerRow2.Cells.Add(CreateSubHeaderCell("Vencido", "chkVencido", "Vencido"))
+ headerRow2.Cells.Add(CreateSubHeaderCell("PorVencer", "chkPorVencer", "Por Vencer"))
+
+ headerRow2.TableSection = TableRowSection.TableHeader
+ grid.Controls(0).Controls.AddAt(1, headerRow2)
+ End If
+ End Sub
+
+ Protected Sub gvCarteraPorVendedor_RowCreated(sender As Object, e As GridViewRowEventArgs)
+ If e.Row.RowType = DataControlRowType.Header Then
+ e.Row.Cells.Clear()
+ Dim grid As GridView = DirectCast(sender, GridView)
+
+ ' --- Fila 1 ---
+ Dim headerRow1 As New GridViewRow(0, 0, DataControlRowType.Header, DataControlRowState.Normal)
+
+ ' Celda principal (Sucursal)
+ Dim cellSucursal As New TableHeaderCell()
+ cellSucursal.RowSpan = 2
+ cellSucursal.VerticalAlign = VerticalAlign.Middle
+ cellSucursal.Controls.Add(New LiteralControl("Vendedor "))
+ Dim hypGrafica As New HyperLink()
+ hypGrafica.NavigateUrl = "javascript:void(0);"
+ hypGrafica.Attributes.Add("onclick", "return generarGrafica('" & grid.ClientID & "');")
+ hypGrafica.CssClass = "grafica-icon"
+ hypGrafica.Controls.Add(New LiteralControl(""))
+ cellSucursal.Controls.Add(hypGrafica)
+ headerRow1.Cells.Add(cellSucursal)
+
+ headerRow1.TableSection = TableRowSection.TableHeader
+ grid.Controls(0).Controls.AddAt(0, headerRow1)
+
+ ' --- Fila 2 (Subheaders) ---
+ Dim headerRow2 As New GridViewRow(1, 0, DataControlRowType.Header, DataControlRowState.Normal)
+
+ ' Subheaders con checkboxes
+ headerRow2.Cells.Add(CreateSubHeaderCell("TotalCxC", "chkTotalCxC", "Total CxC"))
+ headerRow2.Cells.Add(CreateSubHeaderCell("Vencido", "chkVencido", "Vencido"))
+ headerRow2.Cells.Add(CreateSubHeaderCell("PorVencer", "chkPorVencer", "Por Vencer"))
+
+ headerRow2.TableSection = TableRowSection.TableHeader
+ grid.Controls(0).Controls.AddAt(1, headerRow2)
+ End If
+ End Sub
+
+ '''
+ ''' Ahora emitimos HTML puro para el checkbox + label,
+ ''' así el label realmente dispara el toggle del input.
+ '''
+ Private Function CreateSubHeaderCell(text As String, checkboxId As String, dataField As String) As TableHeaderCell
+ Dim cell As New TableHeaderCell()
+ cell.HorizontalAlign = HorizontalAlign.Center
+
+ ' Construimos un pequeño bloque HTML con y