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