private string Procesar(int iNumPSN_Origen, int iNumPSN_Destino, bool bBitacoraPT, bool bBitacoraTA, bool bHitos,
                            string sEstadosTarea, string ID_PROYECTOSUBNODO, string MODOLECTURA_PROYECTOSUBNODO,
                            string RTPT_PROYECTOSUBNODO, string MONEDA_PROYECTOSUBNODO, string sAccDoc, bool bCopiaAE)
    {
        string sResul = "";
        string sModelotarif_Origen  = "";
        string sModelotarif_Destino = "";
        bool   bErrorControlado     = false;
        int    iNodoOrigen          = 0;
        int    iNodoDestino         = 0;
        int    iNumPE_Origen        = 0;
        int    iNumPE_Destino       = 0;

        #region Validaciones previas a la copia de la estructura del proyecto

        try
        {
            //  Comprobaciones de servidor

            /*  - Si un proyecto económico destino tiene consumos
             *  - Los nodos de los proyectos origen y destino deben ser los mismos
             *  - El proyecto destino debe tener el atributo t305_admiterecursospst con valor a 1
             *  - El modelo de tarificación de los proyectos origen y destino deben ser los mismos
             *  - En el proyecto origen debe tener alguna figura en escritura para poder realizarse la copia.
             *    Es decir debe ser:
             *      - Responsable de Oficina Técnica del nodo del proyecto
             *          - Responsable, Delegado, Colaborador de proyecto
             *          - Responsable técnico de proyecto económico (RTPE)
             *          - Jefe de proyecto
             *      - Administrador
             */
            if (bTieneConsumosPE(iNumPSN_Destino))
            {
                bErrorControlado = true;
                throw (new Exception("El proyecto destino tiene consumos.\n\nNo se puede realizar el proceso."));
            }

            SqlDataReader dr = PROYECTO.fgGetDatosProy2(iNumPSN_Origen);
            if (dr.Read())
            {
                iNodoOrigen         = int.Parse(dr["t303_idnodo"].ToString());
                iNumPE_Origen       = int.Parse(dr["t301_idproyecto"].ToString());
                sModelotarif_Origen = dr["t301_modelotarif"].ToString();
            }

            dr = PROYECTO.fgGetDatosProy2(iNumPSN_Destino);
            if (dr.Read())
            {
                if ((bool)dr["t305_admiterecursospst"] == false)
                {
                    dr.Close();
                    dr.Dispose();
                    bErrorControlado = true;
                    throw (new Exception("El proyecto destino debe tener el atributo 'Permitir PST' activado.\n\nNo se puede realizar el proceso."));
                }
                iNodoDestino         = int.Parse(dr["t303_idnodo"].ToString());
                iNumPE_Destino       = int.Parse(dr["t301_idproyecto"].ToString());
                sModelotarif_Destino = dr["t301_modelotarif"].ToString();
            }
            dr.Close();
            dr.Dispose();

            //if (iNodoOrigen != iNodoDestino)
            //{
            //    bErrorControlado = true;
            //    throw (new Exception("Los nodos de los proyectos origen y destino son diferentes.\n\nNo se puede realizar el proceso."));
            //}

            if (sModelotarif_Origen != sModelotarif_Destino)
            {
                bErrorControlado = true;
                throw (new Exception("Los modelos de tarificación de los proyectos origen y destino son diferentes.\n\nNo se puede realizar el proceso."));
            }

            bool bModoEscritura = false;
            dr = PROYECTOSUBNODO.FigurasModoEscritura(null, iNumPSN_Origen, (int)Session["UsuarioActual"]);
            if (dr.HasRows)
            {
                bModoEscritura = true;
            }
            if (Session["ADMINISTRADOR_PC_ACTUAL"].ToString() != "")
            {
                bModoEscritura = true;
            }
            dr.Close();
            dr.Dispose();

            if (!bModoEscritura)
            {
                bErrorControlado = true;
                throw (new Exception("Debe tener acceso al proyecto origen en modo escritura.\n\nNo se puede realizar el proceso."));
            }
        }
        catch (Exception ex)
        {
            if (!bErrorControlado)
            {
                sResul = "Error@#@" + Errores.mostrarError("Error en las validaciones previas al proceso", ex);
            }
            else
            {
                sResul = "Error@#@Operación rechazada.\n\n" + ex.Message;
            }
            return(sResul);
        }

        #endregion

        #region abrir conexión y transacción
        try
        {
            oConn = Conexion.Abrir();
            tr    = Conexion.AbrirTransaccion(oConn);
        }
        catch (Exception ex)
        {
            if (oConn.State == ConnectionState.Open)
            {
                Conexion.Cerrar(oConn);
            }
            sResul = "Error@#@" + Errores.mostrarError("Error al abrir la conexión", ex);
            return(sResul);
        }
        #endregion

        try
        {
            PROYECTOSUBNODO.Duplicar(tr, iNumPSN_Origen, iNumPSN_Destino, iNumPE_Origen, iNumPE_Destino,
                                     bBitacoraPT, bBitacoraTA, bHitos, sEstadosTarea, (int)Session["UsuarioActual"], sAccDoc, bCopiaAE);

            Conexion.CommitTransaccion(tr);
            sResul = "OK@#@";
        }
        catch (Exception ex)
        {
            Conexion.CerrarTransaccion(tr);

            if (!bErrorControlado)
            {
                sResul = "Error@#@" + Errores.mostrarError("Error al grabar datos de la estructura del proyecto", ex);
            }
            else
            {
                sResul = "Error@#@Operación rechazada.\n\n" + ex.Message;
            }
        }
        finally
        {
            Conexion.Cerrar(oConn);
        }

        /* Se restauran los valores que se han modificado al seleccionar el proyecto origen */
        Session["ID_PROYECTOSUBNODO"]          = int.Parse(ID_PROYECTOSUBNODO);
        Session["MODOLECTURA_PROYECTOSUBNODO"] = (MODOLECTURA_PROYECTOSUBNODO == "1") ? true : false;
        Session["RTPT_PROYECTOSUBNODO"]        = (RTPT_PROYECTOSUBNODO == "1") ? true : false;
        Session["MONEDA_PROYECTOSUBNODO"]      = MONEDA_PROYECTOSUBNODO;

        return(sResul);
    }