martes, 29 de septiembre de 2009

Pasando variables entre páginas aspx

No me andaré con rodeos...

Esto en la pagina q llama
Context.Items("usr") = "1001" 
Context.Items("nam") = "Rene" 
Context.Items("Memo") = " Aki va el texto "
Server.Transfer("WebForm2.aspx") <- pagina a la q se llama 
y en la q se llama lee asi los valores:
txtusr.Text = Context.Items("usr") 
txtNam.Text = Context.Items("nam") 
txtMemo.Text = Context.Items("Memo") 

miércoles, 23 de septiembre de 2009

Cómo ocultar pestañas (tabs) en los formularios del CRM 4.0

Una vez más hay que recurrir a Javascript. En el evento OnLoad() del formulario hay que poner el siguiente código:

if (UserHasRole("Administrador")) {   
   crmForm.all.tab1Tab.style.display = 'inline';
}
else {  
   crmForm.all.tab1Tab.style.display = 'none';
}

Fijaros en tab1Tab donde el número indica el ordinal de la pestaña que queremos ocultar, como los arrays, empieza por cero. He reutilizado la función UserHasRole() de la que ya hablé en el post Cómo habilitar un campo en función del rol del usuario.

Fuente: Todo Microsoft CRM

jueves, 17 de septiembre de 2009

Cómo habilitar un campo en función del rol del usuario

Abrimos las propiedades del formulario.
Seleccionamos el evento OnLoad y pulsamos en el botón Editar.
Acuérdate de marcar el check "El evento está habilitado" porque si no, no funciona el codigo javascript que metas.

El código que tienes que meter dentro de function OnLoad() es:
if (UserHasRole("Director Ventas") || UserHasRole("Director Compras")) {    
   document.forms[0].all.new_validacioncomercial_d.disabled=false;
} 
else {   
   document.forms[0].all.new_validacioncomercial_d.disabled=true;
}


/* *************************************************** */


function UserHasRole(roleName)  
{  
   //oXml es un objeto que llama a obtener el rol  
   var oXml = GetCurrentUserRoles();  
   if(oXml != null)  
   {  
      //Selecciono el nodo Texto  
      var roles = oXml.selectNodes("//BusinessEntity/q1:name");  
      if(roles != null)  
      {  
         for( i = 0; i < roles.length; i++)  
         {      
            if(roles[i].text == roleName)  
            {  
               //Devuelve true si el rol es el indicado  
               return true; 
            }  
         }   
      }  
   }  
   //Sino devuelve falso  
   return false;  
}  


function GetCurrentUserRoles()  
{
   // Compongo el xml 
   var xml = "" +  
   "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +  
   "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">" +  
   GenerateAuthenticationHeader() +  
   " <soap:Body>" +  
   " <RetrieveMultiple xmlns=\"http://schemas.microsoft.com/crm/2007/WebServices\">" +  
   " <query xmlns:q1=\"http://schemas.microsoft.com/crm/2006/Query\" xsi:type=\"q1:QueryExpression\">" +  
   " <q1:EntityName>role</q1:EntityName>" +  
   " <q1:ColumnSet xsi:type=\"q1:ColumnSet\">" +  
   " <q1:Attributes>" +  
   " <q1:Attribute>name</q1:Attribute>" +  
   " </q1:Attributes>" +  
   " </q1:ColumnSet>" +  
   " <q1:Distinct>false</q1:Distinct>" +  
   " <q1:LinkEntities>" +  
   " <q1:LinkEntity>" +  
   " <q1:LinkFromAttributeName>roleid</q1:LinkFromAttributeName>" +  
   " <q1:LinkFromEntityName>role</q1:LinkFromEntityName>" +  
   " <q1:LinkToEntityName>systemuserroles</q1:LinkToEntityName>" +  
   " <q1:LinkToAttributeName>roleid</q1:LinkToAttributeName>" +  
   " <q1:JoinOperator>Inner</q1:JoinOperator>" +  
   " <q1:LinkEntities>" +  
   " <q1:LinkEntity>" +  
   " <q1:LinkFromAttributeName>systemuserid</q1:LinkFromAttributeName>" +  
   " <q1:LinkFromEntityName>systemuserroles</q1:LinkFromEntityName>" +   " <q1:LinkToEntityName>systemuser</q1:LinkToEntityName>" +  
   " <q1:LinkToAttributeName>systemuserid</q1:LinkToAttributeName>" +    " <q1:JoinOperator>Inner</q1:JoinOperator>" +  
   " <q1:LinkCriteria>" +  
   " <q1:FilterOperator>And</q1:FilterOperator>" +  
   " <q1:Conditions>" +  
   " <q1:Condition>" +  
   " <q1:AttributeName>systemuserid</q1:AttributeName>" +  
   " <q1:Operator>EqualUserId</q1:Operator>" +  
   " </q1:Condition>" +  
   " </q1:Conditions>" +  
   " </q1:LinkCriteria>" +  
   " </q1:LinkEntity>" +  
   " </q1:LinkEntities>" +  
   " </q1:LinkEntity>" +  
   " </q1:LinkEntities>" +  
   " </query>" +  
   " </RetrieveMultiple>" +  
   " </soap:Body>" +  
   "</soap:Envelope>" +  
   "";  
   var xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP");  
   xmlHttpRequest.Open("POST", "/mscrmservices/2007/CrmService.asmx", false);  
   xmlHttpRequest.setRequestHeader("SOAPAction"," http://schemas.microsoft.com/crm/2007/WebServices/RetrieveMultiple");  
   xmlHttpRequest.setRequestHeader("Content-Type", "text/xml; charset=utf-8");  
   xmlHttpRequest.setRequestHeader("Content-Length", xml.length);  
   xmlHttpRequest.send(xml);  
   var resultXml = xmlHttpRequest.responseXML;  
   return(resultXml);  
}

Controlar cuando cierra el usuario el navegador

Controlar cuando el usuario nos cierra el navegador ¿Es posible?
Pues sí, es posible, empleando un pequeño truquillo en la maquetación en nuestro Site.

En el cliente en el que me encuentro actualmente me lo pidieron como requisito indispensable, puesto que intentan asemejar el comportamiento de sus aplicaciones Winform y ademas así liberar todos los objetos asociados a esa sesión. Otro requerimiento es que un usuario sólo pueda abrir un ventana de IExplorer para cada aplicación, pero esto lo veremos en la siguiente entrega.

Como comenté en el primer párrafo todo se basa en el modélo de maquetación del site. Es necesario tener una página que nunca se descargue y que solo se dispare su evento JavaScript OnUnload bien cuando nos cierre el navegador de la dichosa X o cuando pulse nuestro botón de desconexión, por lo tanto vamos a utilizar una página principal que sea contenedora de otras páginas mediante un IFRAME:
<div id="content">
<iframe id="contenido" src="contenido1.aspx" frameBorder="0" width="100%" height="400">
</div>
En el IFRAME se realizará la navegación de nuestro Site y así podremos controlar cuando nos cierra el navegador ¿Pero como? pues sencillo, lo controlaremos con un campo oculto:
<input id="logout" type="hidden" value="0">
al que asignaremos un valor distinto de 0 desde nuestro botón de desconexión desde el Code-Behind:
private void imgBtnSalir_Click(object sender, System.Web.UI.ImageClickEventArgs e) 
{
   FormsAuthentication.SignOut();
   Session.Abandon();
   Page.RegisterStartupScript("logout", "<script>document.getElementById(\"logout\").value=1;</script>");
   Page.RegisterStartupScript("close","<script>window.close();</script>");
}
Y en el evento JavaScript OnUnload comprobamos ese valor con la función Logout (<body OnUnload="Logout();">):
function Logout() 
{
   var logout = document.getElementById("logout");
   if (logout.value == 0)
   {
      openCenterPopUp("logout.aspx", "", 600, 70);
   }
} 

Si es 0, abrimos la ventana logout.aspx que se encarga de liberar los recursos de la sesión y de hacer un logout de la autenticación (Aunque yo esto no lo hago en mi cliente puesto que es una intranet y utilizo la autenticación de Windows integrada pero para el ejemplo he preferido añadirlo):

private void Page_Load(object sender, System.EventArgs e)
{
   FormsAuthentication.SignOut();
   Session.Abandon();
   this.RegisterStartupScript("close", "<script>setTimeout(\"window.close();\",10000);</script>");
}

Fuente: esto lo saqué del blog "Amigo mío Siempre estas Programando en .NET"

Abrir distintas versiones de proyectos Asp.Net

Si tienes que abrir un proyecto creado con Visual Studio (VS) 2002 con VS2003 simplemente hay que editar con el bloc de notas el fichero .vbproj y cambiar los siguientes datos:
En el caso de los proyectos creados con VS2002 guarda esta información:
ProductVersion = "7.0.9466"
SchemaVersion = "1.0"

Mientras que la versión 2003, guardará esta información:
ProductVersion = "7.10.2292"
SchemaVersion = "2.0"

Cambia uno por otro y listo!
Para versiones posteriores, Visual Studio ya dispone de un conversor automático.

CRM: Empezando...

Este post es para todo aquel que se va a enfrentar a la personalización del CRM de su empresa.
Para empezar ¿qué es un CRM? las siglas son de "Customer Relationship Management" ¿lo cualo? sí tranquil@, no es ni más ni menos que una aplicación web de Microsoft orientada a la gestión de todo lo que tenga que ver con el cliente en tu empresa. Es decir, gestión de contactos, cuentas, clientes potenciales, ofertas, pedidos, campañas de marketing, catálogo de productos, etc... todo ello "salvaguardado" por un sistema de seguridad basado en roles de usuario.

¿Cómo meterle mano a esto?
El CRM de Microsoft se basa en "entidades", es algo parecido a los objetos en programación. Una entidad "Contacto" tiene una serie de atributos como "Nombre", "Teléfono", etc... además puede estar relacionada con otras entidades 1:N, N:1 o N:N. En el apartado Personalización del módulo Configuración tenéis el listado de todas ellas. Se pueden crear nuevas entidades.

¿Y cómo programo algo para el CRM?
Pues hay varias opciones, incluyendo JavaScript en los eventos de los formularios, desarrollando en Asp.Net un aspx y agregar un iFrame al formulario de la entidad cuyo contenido será este aspx, desarrollando un Plugin o hacer llamadas a WebServices.

Poco a poco iré publicando las utilidades que desarrolle o que haya encontrado por ahí.

INTRODUCCION

Este blog pretende ser un compendio de trozos de código que puedan echar una mano a otros desarrollador@s. Las tecnologías y lenguajes serán variados, pero casi siempre centrándose en productos Microsoft.
Muchos post serán una especie de corta/pega de otros, se pondrán las referencias originales a esos post por si queréis más información.