lunes, 22 de septiembre de 2025

.NET C# grilla dinámica desde SP

 .ASPX

<%@ Page Title="Informe Bienes Asegurados" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="InformeBienesAsegurados.aspx.cs" Inherits="LeaseOperWeb.Paginas.AdmSeguros.Consultas.InformeBienesAsegurados" %>


<%@ Register Assembly="DevExpress.Web.ASPxEditors.v11.1, Version=11.1.8.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a"

    Namespace="DevExpress.Web.ASPxEditors" TagPrefix="dx" %>

<%@ Register Assembly="DevExpress.Web.v11.1, Version=11.1.8.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a"

    Namespace="DevExpress.Web.ASPxPanel" TagPrefix="dx" %>

<%@ Register Assembly="DevExpress.Web.ASPxGridView.v11.1, Version=11.1.8.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a"

    Namespace="DevExpress.Web.ASPxGridView" TagPrefix="dx" %>


<asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" runat="server">

     


    <script type="text/javascript">

        // ===== Utilidades =====

        var _rutMsgShown = false;

        function _onceRutInvalidMessage() {

            if (_rutMsgShown) return false;

            _rutMsgShown = true;

            showMessage('RUT Cliente no es válido.', 'Validación');

            // liberar el lock después de un tick (evita múltiples eventos encadenados)

            setTimeout(function () { _rutMsgShown = false; }, 300);

            return true;

        }


        function onlyDigits(e) {

            var k = e.which || e.keyCode;

            if (k === 8 || k === 9 || k === 46 || (k >= 35 && k <= 40)) return true;

            if (k >= 48 && k <= 57) return true;

            if (k >= 96 && k <= 105) return true;

            return false;

        }

        function cleanRut(r) { return (r || "").toString().replace(/\./g, '').replace(/-/g, '').toUpperCase(); }

        function dvRut(num) { var M = 0, S = 1; for (; num; num = Math.floor(num / 10)) S = (S + num % 10 * (9 - M++ % 6)) % 11; return S ? String(S - 1) : 'K'; }

        function formatRut(r) {

            r = cleanRut(r); if (r.length < 2) return r;

            var cuerpo = r.slice(0, -1), dv = r.slice(-1), out = "", i = 0;

            for (var j = cuerpo.length - 1; j >= 0; j--) { out = cuerpo.charAt(j) + out; i++; if (i % 3 === 0 && j !== 0) out = "." + out; }

            return out + "-" + dv;

        }

        function isRutValido(r) {

            r = cleanRut(r); if (r.length < 2) return false;

            var c = r.slice(0, -1), dv = r.slice(-1); if (!/^\d+$/.test(c)) return false;

            return dv.toUpperCase() === dvRut(parseInt(c, 10));

        }

        function formatDateISO(d) {

            if (!d) return "";

            var yyyy = d.getFullYear(), mm = ("0" + (d.getMonth() + 1)).slice(-2), dd = ("0" + d.getDate()).slice(-2);

            return yyyy + "-" + mm + "-" + dd;

        }

        function validarFechas(fechaIni, fechaFin) {

            if ((fechaIni && !fechaFin) || (!fechaIni && fechaFin)) { showMessage('Debe ingresar ambas fechas: Inicio y Término.', 'Validación'); return false; }

            if (fechaIni && fechaFin && fechaIni > fechaFin) { showMessage('La fecha de inicio no puede ser mayor que la fecha de término.', 'Validación'); return false; }

            return true;

        }


        // Sincroniza filtros -> hidden inputs (para Request[...] y callbacks)

        function syncHiddenParams() {

            // RUT

            var rut = txtRutCliente.GetText();

            if (rut) {

                var limpio = cleanRut(rut);

                if (!isRutValido(limpio)) {

                    _onceRutInvalidMessage();

                    txtRutCliente.SetText('');

                    return false;

                }

                rut = formatRut(limpio);

            }


            var op = txtOperacion.GetText();

            if (op && !/^\d{1,20}$/.test(op)) { showMessage('Operación debe ser numérica (máx. 20 dígitos).', 'Validación'); return false; }

            var ult = txtUltimaPoliza.GetText();

            if (ult && !/^\d{1,10}$/.test(ult)) { showMessage('Última Póliza debe ser numérica entera (INT).', 'Validación'); return false; }


            var tipoSeg = cbxTipoSeguro.GetValue();

            var estPol = cbxEstadoPoliza.GetValue();

            var fIni = dtFechaTerminoIni.GetDate();

            var fFin = dtFechaTerminoFin.GetDate();

            if (!validarFechas(fIni, fFin)) return false;


            document.getElementById("rutCliente").value = rut || "";

            document.getElementById("operacion").value = op || "";

            document.getElementById("ultimaPoliza").value = ult || "";

            document.getElementById("tipoSeguro").value = tipoSeg || "";

            document.getElementById("estadoPoliza").value = estPol || "";

            document.getElementById("fechaTerminoIni").value = fIni ? formatDateISO(fIni) : "";

            document.getElementById("fechaTerminoFin").value = fFin ? formatDateISO(fFin) : "";

            return true;

        }


        // Cargar combos dependientes

        function onTipoSeguroChanged(s, e) {

            var tipo = s.GetValue();

            cbxEstadoPoliza.PerformCallback(tipo ? tipo.toString() : "");

        }


        // Buscar -> callback del GRID

        function onBuscarClick() {

            if (!syncHiddenParams()) return;


            var rutCliente = document.getElementById("rutCliente").value || "";

            var operacion = document.getElementById("operacion").value || "";

            var ultimaPoliza = document.getElementById("ultimaPoliza").value || "";

            var tipoSeguro = document.getElementById("tipoSeguro").value || "";

            var estadoPoliza = document.getElementById("estadoPoliza").value || "";

            var fechaTerminoIni = document.getElementById("fechaTerminoIni").value || "";

            var fechaTerminoFin = document.getElementById("fechaTerminoFin").value || "";


            var allEmpty =

                !rutCliente &&

                !operacion &&

                !ultimaPoliza &&

                (tipoSeguro === "0" || tipoSeguro === "") &&

                (estadoPoliza === "0" || estadoPoliza === "") &&

                !fechaTerminoIni &&

                !fechaTerminoFin;


            if (allEmpty) {

                showMessage('Ingrese al menos un criterio de búsqueda para recuperar.', 'Validación');

                return;

            }


            var p =

                rutCliente + "|" +

                operacion + "|" +

                ultimaPoliza + "|" +

                tipoSeguro + "|" +

                estadoPoliza + "|" +

                fechaTerminoIni + "|" +

                fechaTerminoFin;


            gvInforme.PerformCallback(p);

        }



        // Exportar Excel (usa los hidden, mismo orden que el .cs)

        function excel() {

            if (!syncHiddenParams()) return;


            var get = function (id) { return (document.getElementById(id).value || ''); };


            var rutCliente = get('rutCliente');

            var operacion = get('operacion');

            var ultimaPoliza = get('ultimaPoliza');

            var tipoSeguro = get('tipoSeguro');

            var estadoPoliza = get('estadoPoliza');

            var fechaTerminoIni = get('fechaTerminoIni');

            var fechaTerminoFin = get('fechaTerminoFin');



            var allEmpty =

                !rutCliente &&

                !operacion &&

                !ultimaPoliza &&

                (tipoSeguro === "0" || tipoSeguro === "") &&

                (estadoPoliza === "0" || estadoPoliza === "") &&

                !fechaTerminoIni &&

                !fechaTerminoFin;


            if (allEmpty) {

                showMessage('Ingrese al menos un criterio de búsqueda para exportar.', 'Validación');

                return;

            }


            var id_informe = "10031";

            var hoja = "BienesAsegurados";


            var wsdata = "{'iddoc':'" + id_informe +

                "','hoja':'" + hoja +

                "','rutCliente':'" + rutCliente +

                "','operacion':'" + operacion +

                "','ultimaPoliza':'" + ultimaPoliza +

                "','tipoSeguro':'" + tipoSeguro +

                "','estadoPoliza':'" + estadoPoliza +

                "','fechaTerminoIni':'" + fechaTerminoIni +

                "','fechaTerminoFin':'" + fechaTerminoFin + "'}";


            jutils.ajax.getJsonData_Async("ReporteXls", wsdata, arguments.callee.name, showReportExcel);

        }



        function showReportExcel(data) {

            if (data == 'SD') { showMessage('No se encontraron Registros', 'Información'); return; }

            var wsdata = "{}";

            var url = jutils.ajax.getJsonData("GetRutaCargaExcel", wsdata, arguments.callee.name);

            url = url + data;

            var opts = "toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=yes, resizable=yes, width=1, height=1, top=1, left=1";

            window.open(url, '', opts);

        }


        // Formato/validación RUT en vivo

        function onRutKeyUp(s, e) {

            _rutMsgShown = false; // reset al teclear

            var v = s.GetText();

            v = v.replace(/[^\dkK.-]/g, '');

            s.SetText(v);

        }

        function onRutLostFocus(s, e) {

            var v = s.GetText();

            if (!v) return;


            var limpio = cleanRut(v);

            if (!isRutValido(limpio)) {

                // muestra solo 1 vez y limpia

                _onceRutInvalidMessage();

                s.SetText('');

                return;

            }

            s.SetText(formatRut(limpio));

        }


        function onLimpiarClick() {


            txtRutCliente.SetText('');

            txtOperacion.SetText('');

            txtUltimaPoliza.SetText('');



            cbxTipoSeguro.SetSelectedIndex(0); // "No definido"

            cbxEstadoPoliza.ClearItems();



            dtFechaTerminoIni.SetDate(null);

            dtFechaTerminoFin.SetDate(null);



            document.getElementById("rutCliente").value = "";

            document.getElementById("operacion").value = "";

            document.getElementById("ultimaPoliza").value = "";

            document.getElementById("tipoSeguro").value = "";

            document.getElementById("estadoPoliza").value = "";

            document.getElementById("fechaTerminoIni").value = "";

            document.getElementById("fechaTerminoFin").value = "";



            gvInforme.ClearFilter();

            gvInforme.PerformCallback('');

        }


    </script>

</asp:Content>


<asp:Content ID="Content2" ContentPlaceHolderID="HeaderContent" runat="server">

    <!-- Hidden para callbacks/WebMethods -->

    <input type="hidden" id="rutCliente" name="rutCliente" />

    <input type="hidden" id="operacion" name="operacion" />

    <input type="hidden" id="ultimaPoliza" name="ultimaPoliza" />

    <input type="hidden" id="tipoSeguro" name="tipoSeguro" />

    <input type="hidden" id="estadoPoliza" name="estadoPoliza" />

    <input type="hidden" id="fechaTerminoIni" name="fechaTerminoIni" />

    <input type="hidden" id="fechaTerminoFin" name="fechaTerminoFin" />


    <table width="100%" border="0" cellspacing="0" cellpadding="0">

        <tr>

            <td valign="top" id="td-descrip">

                <table width="100%" border="0" cellspacing="0" cellpadding="0">

                    <tr>

                        <td>&nbsp;</td>

                    </tr>

                    <tr>

                        <td class="td-titulos">Informe Bienes ASEGURADOS</td>

                    </tr>

                    <tr>

                        <td>

                            <table width="100%" border="0" cellspacing="0" cellpadding="0">

                                <tr>

                                    <td width="40">&nbsp;</td>

                                    <td class="lin-borde">&nbsp;</td>

                                </tr>

                            </table>

                        </td>

                    </tr>

                    <tr>

                        <td class="mig">Adm. Seguros / Consultas / INFORME BIENES ASEGURADOS</td>

                    </tr>

                </table>

            </td>

        </tr>

        <tr>

            <td valign="top">&nbsp;</td>

        </tr>

        <tr>

            <td valign="top">

                <table width="100%" border="0" cellpadding="0" cellspacing="0">

                    <tr>

                        <td width="10">&nbsp;</td>

                        <td>

                            <asp:UpdatePanel ID="udp" runat="server" UpdateMode="Conditional">

                                <ContentTemplate>

                                    <table width="100%" border="0" cellspacing="0" cellpadding="0">

                                        <tr>

                                            <td valign="top">

                                                <table width="100%" border="0" cellpadding="0" cellspacing="0" class="style2">

                                                    <tr>

                                                        <td>

                                                            <table width="100%" border="0" cellpadding="0" cellspacing="0" class="style2">

                                                                <tr>

                                                                    <td>

                                                                        <table width="100%" border="0" cellspacing="0" cellpadding="0">

                                                                            <tr>

                                                                                <td>

                                                                                    <table width="100%" border="0" cellspacing="0" cellpadding="0" class="borde">

                                                                                        <tr>

                                                                                            <td>

                                                                                                <div class="modul">

                                                                                                    <div class="modul_top">

                                                                                                        <div class="modul_top_right">

                                                                                                            <table width="100%" border="0" cellspacing="0" cellpadding="0">

                                                                                                                <tr>

                                                                                                                    <td width="9"></td>

                                                                                                                    <td class="modul_fd">

                                                                                                                        <table width="100%" border="0" cellspacing="0" cellpadding="0">

                                                                                                                            <tr>

                                                                                                                                <td class="modul_fd_tit">BÚSQUEDA</td>

                                                                                                                            </tr>

                                                                                                                        </table>

                                                                                                                    </td>

                                                                                                                    <td width="9"></td>

                                                                                                                </tr>

                                                                                                            </table>

                                                                                                        </div>

                                                                                                    </div>

                                                                                                    <div id="modul_content"></div>

                                                                                                </div>

                                                                                            </td>

                                                                                        </tr>

                                                                                    </table>

                                                                                </td>

                                                                            </tr>

                                                                            <tr>

                                                                                <td class="modul_bordes">

                                                                                    <table width="100%" border="0" cellspacing="0" cellpadding="0" class="caja-datos">

                                                                                        <tr>

                                                                                            <td width="10"></td>

                                                                                            <td height="10"></td>

                                                                                            <td width="10"></td>

                                                                                        </tr>

                                                                                        <tr>

                                                                                            <td rowspan="2"></td>

                                                                                            <td>

                                                                                                <!-- ===== Filtros ===== -->

                                                                                                <table class="style2" style="margin-bottom: 8px;">

                                                                                                    <tr>

                                                                                                        <td>RUT Cliente:</td>

                                                                                                        <td>

                                                                                                            <dx:ASPxTextBox ID="txtRutCliente" runat="server" Width="150" ClientInstanceName="txtRutCliente" MaxLength="12">

                                                                                                                <ClientSideEvents KeyUp="onRutKeyUp" LostFocus="onRutLostFocus" />

                                                                                                            </dx:ASPxTextBox>

                                                                                                            <span style="font-size: 10px; color: #666;">(11.111.111-1)</span>

                                                                                                        </td>

                                                                                                        <td>Operación:</td>

                                                                                                        <td>

                                                                                                            <dx:ASPxTextBox ID="txtOperacion" runat="server" Width="150" ClientInstanceName="txtOperacion" MaxLength="20">

                                                                                                                <ClientSideEvents KeyPress="function(s,e){ if(!onlyDigits(e)) e.preventDefault(); }" />

                                                                                                            </dx:ASPxTextBox>

                                                                                                        </td>

                                                                                                        <td>Última Póliza:</td>

                                                                                                        <td>

                                                                                                            <dx:ASPxTextBox ID="txtUltimaPoliza" runat="server" Width="150" ClientInstanceName="txtUltimaPoliza" MaxLength="10">

                                                                                                                <ClientSideEvents KeyPress="function(s,e){ if(!onlyDigits(e)) e.preventDefault(); }" />

                                                                                                            </dx:ASPxTextBox>

                                                                                                        </td>

                                                                                                        <td>Tipo Seguro:</td>

                                                                                                        <td>

                                                                                                            <dx:ASPxComboBox ID="cbxTipoSeguro" ClientInstanceName="cbxTipoSeguro" runat="server" Width="150" ValueType="System.String">

                                                                                                                <Items>

                                                                                                                    <dx:ListEditItem Value="0" Text="No definido" Selected="True" />

                                                                                                                    <dx:ListEditItem Value="1" Text="Seguro Banco" />

                                                                                                                    <dx:ListEditItem Value="2" Text="Seguro Cliente" />

                                                                                                                </Items>

                                                                                                                <ClientSideEvents SelectedIndexChanged="onTipoSeguroChanged" />

                                                                                                            </dx:ASPxComboBox>

                                                                                                        </td>

                                                                                                    </tr>

                                                                                                    <tr>

                                                                                                        <td>Estado Póliza:</td>

                                                                                                        <td>

                                                                                                            <dx:ASPxComboBox ID="cbxEstadoPoliza"

                                                                                                                ClientInstanceName="cbxEstadoPoliza"

                                                                                                                runat="server"

                                                                                                                Width="150"

                                                                                                                ValueType="System.String"

                                                                                                                OnCallback="cbxEstadoPoliza_Callback" />

                                                                                                        </td>

                                                                                                        <td>Fecha Término Ini:</td>

                                                                                                        <td>

                                                                                                            <dx:ASPxDateEdit ID="dtFechaTerminoIni" ClientInstanceName="dtFechaTerminoIni" runat="server" Width="150" />

                                                                                                        </td>

                                                                                                        <td>Fecha Término Fin:</td>

                                                                                                        <td>

                                                                                                            <dx:ASPxDateEdit ID="dtFechaTerminoFin" ClientInstanceName="dtFechaTerminoFin" runat="server" Width="150" />

                                                                                                        </td>

                                                                                                        <td>&nbsp;</td>

                                                                                                        <td>&nbsp;</td>

                                                                                                    </tr>

                                                                                                </table>


                                                                                                <!-- Botones -->

                                                                                                <table class="style2">

                                                                                                    <tr>

                                                                                                        <td>

                                                                                                            <dx:ASPxButton ID="btnBuscar" runat="server" AutoPostBack="false"

                                                                                                                CssClass="btn_buscar" ClientInstanceName="btnBuscar" Cursor="pointer"

                                                                                                                EnableDefaultAppearance="False" EnableTheming="False" Text="Recuperar">

                                                                                                                <ClientSideEvents Click="function(s, e){ onBuscarClick(); }" />

                                                                                                            </dx:ASPxButton>

                                                                                                        </td>

                                                                                                        <td>&nbsp;</td>

                                                                                                        <td>

                                                                                                            <input type="button" value="Exportar" name="btnImprimir" onclick="excel();" class="btn_excel" /></td>

                                                                                                        <td>

                                                                                                            <dx:ASPxButton ID="btnLimpiar" runat="server" AutoPostBack="false"

                                                                                                                CssClass="btn_limpiar" ClientInstanceName="btnLimpiar" Cursor="pointer"

                                                                                                                EnableDefaultAppearance="False" EnableTheming="False" Text="Limpiar">

                                                                                                                <ClientSideEvents Click="function(s, e){ onLimpiarClick(); }" />

                                                                                                            </dx:ASPxButton>

                                                                                                        </td>

                                                                                                    </tr>

                                                                                                </table>

                                                                                            </td>

                                                                                            <td>&nbsp;</td>

                                                                                        </tr>

                                                                                    </table>

                                                                                </td>

                                                                            </tr>

                                                                            <tr>

                                                                                <td>

                                                                                    <div class="modul_bottom">

                                                                                        <div class="modul_bottom_right">

                                                                                            <div class="modul_borde-bottom"></div>

                                                                                        </div>

                                                                                    </div>

                                                                                </td>

                                                                            </tr>

                                                                        </table>

                                                                    </td>

                                                                </tr>

                                                            </table>

                                                        </td>

                                                    </tr>

                                                </table>

                                            </td>

                                        </tr>

                                        <tr>

                                            <td valign="top">&nbsp;</td>

                                        </tr>


                                        <!-- ===== GRID EN PANTALLA ===== -->

                                        <tr>

                                            <td valign="top">

                                                <dx:ASPxGridView ID="gvInforme" runat="server"

                                                    ClientInstanceName="gvInforme"

                                                    Width="100%" AutoGenerateColumns="True"

                                                    OnCustomCallback="gvInforme_CustomCallback">

                                                    <Settings ShowGroupPanel="False" />

                                                    <SettingsBehavior AllowGroup="False" />

                                                    <SettingsText GroupPanel="" />

                                                    <Settings ShowHorizontalScrollBar="true" ShowVerticalScrollBar="true" VerticalScrollableHeight="320" />

                                                    <SettingsPager Mode="ShowAllRecords" />

                                                </dx:ASPxGridView>




                                            </td>

                                        </tr>

                                    </table>

                                </ContentTemplate>

                            </asp:UpdatePanel>

                        </td>

                        <td width="10">&nbsp;</td>

                    </tr>

                </table>

            </td>

        </tr>

    </table>

</asp:Content>



.CS

using System;
using System.Data;
using System.Globalization;
using System.Web.Services;
using DevExpress.Web.ASPxGridView;
using LeaOperBussinesLayer.BussinesComponents.AdmSeguros.SolicitudSeguros;
using LeaseOperWeb.Negocio.Comun;
using LeaseOperWeb.Utils;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Web.UI.WebControls;
using DevExpress.Web.ASPxGridView;


namespace LeaseOperWeb.Paginas.AdmSeguros.Consultas
{
    public partial class InformeBienesAsegurados : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e) { }

        protected void cbxEstadoPoliza_Callback(object source, DevExpress.Web.ASPxClasses.CallbackEventArgsBase e)
        {
            cbxEstadoPoliza.Items.Clear();

            int ts;
            if (int.TryParse(e.Parameter, out ts) && (ts == 1 || ts == 2))
            {
                DataTable dt = new SolicitudSegurosBc().ListarEstadosPolizaPorTipoSeguro(ts);
                if (dt != null)
                {
                    foreach (DataRow r in dt.Rows)
                    {
                        var text = Convert.ToString(r["desc_valor"]);
                        var val = Convert.ToString(r["valor"]);
                        cbxEstadoPoliza.Items.Add(text, val);
                    }
                    if (cbxEstadoPoliza.Items.Count > 0) cbxEstadoPoliza.SelectedIndex = 0;
                }
            }
        }


        protected void gvInforme_CustomCallback(object sender, ASPxGridViewCustomCallbackEventArgs e)
        {
            try
            {
                string[] p = (e.Parameters ?? "").Split('|');
                string rutCliente = p.Length > 0 ? p[0] : string.Empty;
                string operacion = p.Length > 1 ? p[1] : string.Empty;
                string ultimaPoliza = p.Length > 2 ? p[2] : string.Empty;
                string tipoSeguro = p.Length > 3 ? p[3] : string.Empty;
                string estadoPoliza = p.Length > 4 ? p[4] : string.Empty;
                string fechaTerminoIni = p.Length > 5 ? p[5] : string.Empty;
                string fechaTerminoFin = p.Length > 6 ? p[6] : string.Empty;

                int rutCliente0 = RutSinDv(rutCliente);                  
                long operacion0 = ToNullableLong(operacion) ?? 0L;
                int ultimaPoliza0 = ToNullableInt(ultimaPoliza) ?? 0;
                int tipoSeguro0 = ToNullableInt(tipoSeguro) ?? 0;
                int estadoPoliza0 = ToNullableInt(estadoPoliza) ?? 0;
                DateTime? fechaIni = ToNullableDate(fechaTerminoIni);
                DateTime? fechaFin = ToNullableDate(fechaTerminoFin);

                byte? tipoSalida = 1;

                DataTable raw = new SolicitudSegurosBc().ListarPolizasClientesBienesAsegurados(
                    tipoSalida, rutCliente0, operacion0, ultimaPoliza0, tipoSeguro0, estadoPoliza0, fechaIni, fechaFin);

                if (raw == null || raw.Rows.Count == 0)
                {
                    gvInforme.DataSource = null;
                    gvInforme.DataBind();
                    return;
                }

                Dictionary<string, string> captions;
                DataTable dt = SanitizeColumns(raw, out captions);
                BuildGridColumns(dt, captions);

                gvInforme.DataSource = dt;
                gvInforme.DataBind();
            }
            catch
            {
                gvInforme.DataSource = null;
                gvInforme.DataBind();
            }
        }





        private static int? ToNullableInt(string s)
        {
            if (int.TryParse(s, out var v)) return v;
            return null;
        }

        private static long? ToNullableLong(string s)
        {
            if (long.TryParse(s, out var v)) return v;
            return null;
        }

        private static DateTime? ToNullableDate(string s)
        {
            if (string.IsNullOrWhiteSpace(s)) return null;
            if (DateTime.TryParseExact(s, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out var d))
                return d;
            if (DateTime.TryParse(s, out d)) return d;
            return null;
        }
        [WebMethod]
        public static string ReporteXls(
            string iddoc,
            string hoja,
            string rutCliente,
            string operacion,
            string ultimaPoliza,
            string tipoSeguro,
            string estadoPoliza,
            string fechaTerminoIni,
            string fechaTerminoFin)
        {
            string salida = string.Empty;
            try
            {
                int rutCliente0 = RutSinDv(rutCliente);
                long operacion0 = ToNullableLong(operacion) ?? 0L;
                int ultimaPoliza0 = ToNullableInt(ultimaPoliza) ?? 0;
                int tipoSeguro0 = ToNullableInt(tipoSeguro) ?? 0;
                int estadoPoliza0 = ToNullableInt(estadoPoliza) ?? 0;
                DateTime? fechaIni = ToNullableDate(fechaTerminoIni);
                DateTime? fechaFin = ToNullableDate(fechaTerminoFin);

                byte? tipoSalida = 1;

                DataTable dt = new SolicitudSegurosBc().ListarPolizasClientesBienesAsegurados(
                    tipoSalida, rutCliente0, operacion0, ultimaPoliza0, tipoSeguro0, estadoPoliza0, fechaIni, fechaFin);

                if (dt == null || dt.Rows.Count == 0)
                    return JsonConvert.SerializeObject("SD");

                string sheet = string.IsNullOrWhiteSpace(hoja) ? "BienesAsegurados" : hoja;
                salida = FuncionesGenericasWebBc.bajarExcel(dt, sheet);
            }
            catch (Exception exc)
            {
                salida = "*" + exc.Message.Replace("'", " ") + "*";
            }
            return JsonConvert.SerializeObject(salida);
        }



        [WebMethod]
        public static string GetRutaCRError()
        {
            return JsonConvert.SerializeObject(new FuncionesGenericas().MapPathURLCRError());
        }

        [WebMethod]
        public static string GetRutaCargaExcel()
        {
            return JsonConvert.SerializeObject(new FuncionesGenericas().MapPathURLExcelDownLoad());
        }

        private static int RutSinDv(string rut)
        {
            if (string.IsNullOrWhiteSpace(rut)) return 0;
            string s = (rut ?? "").Trim().ToUpper().Replace(".", "");
            int guion = s.IndexOf('-');
            if (guion > 0) s = s.Substring(0, guion);
            else if (s.Length > 1) s = s.Substring(0, s.Length - 1);
            int v; return int.TryParse(s, out v) ? v : 0;
        }

        private static DataTable SanitizeColumns(DataTable src, out Dictionary<string, string> captions)
        {
            captions = new Dictionary<string, string>();
            var dt = src.Copy();

            foreach (DataColumn c in dt.Columns)
            {
                string original = c.ColumnName;
                string safe = Regex.Replace(original, @"[^\w]", "_");   // reemplaza espacios, puntos, etc.
                safe = Regex.Replace(safe, "_{2,}", "_");               // colapsa __
                if (char.IsDigit(safe[0])) safe = "_" + safe;           // no iniciar con dígito
                if (safe != original) c.ColumnName = safe;
                captions[c.ColumnName] = original;                      // guarda caption
            }
            return dt;
        }

        private void BuildGridColumns(DataTable dt, IDictionary<string, string> captions)
        {
            gvInforme.Columns.Clear();
            gvInforme.KeyFieldName = dt.Columns.Contains("ID") ? "ID" : dt.Columns[0].ColumnName;

            foreach (DataColumn col in dt.Columns)
            {
                var gcol = new GridViewDataTextColumn
                {
                    FieldName = col.ColumnName,
                    Caption = captions.ContainsKey(col.ColumnName) ? captions[col.ColumnName] : col.ColumnName
                };

                if (col.DataType == typeof(DateTime))
                    gcol.PropertiesTextEdit.DisplayFormatString = "dd/MM/yyyy";

                if (col.DataType == typeof(decimal) || col.DataType == typeof(double) || col.DataType == typeof(float) || col.DataType == typeof(int) || col.DataType == typeof(long))
                    gcol.CellStyle.HorizontalAlign = HorizontalAlign.Right;

                gvInforme.Columns.Add(gcol);
            }
        }


    }
}