29 de diciembre de 2014

Project Server 2013. Impedir editar un Custom Field en una PDP

Recientemente tuve la necesidad de impedir modificar un campo de empresa (CF = Custom Field) en una Project Detail Page (PDP).

En la instancia de Project Server 2013, existía un CF (Project ID), este CF se generaba de forma automática. Se deseaba poder mostrar este CF en las PDP pero que no pudiera ser editado.

Normalmente esta problemática la resolveríamos controlando el CF según el WorkFlow, pero el tipo de proyecto en cuestión no tenia asociado un WorkFlow.

Solución

Para solucionarlo implementamos una simple función jQuery que deshabilitara el CF, siguiendo los siguientes pasos:

  • En todas las PDP donde se incluya el CF Project ID, deberemos agregar un WebPart (WP) de tipo (Script Editor).
  • El WP deberemos posicionarlo al final de página.
  • El WP contendrá el siguiente código:

<script src="https://code.jquery.com/jquery-2.1.3.min.js"></script>

 

<script type="text/javascript">

       $(document).ready(function () {

             $("input[title='Project ID']").attr('disabled', 'disabled');

       });

</script>

 

Y con esto queda solucionado el problema, aunque estemos editando el proyecto, el CF aparecerá como deshabilitado.

14 de diciembre de 2014

Como saber en Project Server si un proyecto está Check-Out

Para saber en Project Server si un determinado proyecto está desprotegido (Check Out) podemos usar la siguiente función:

public bool ProjectIsCheckOut(string projUid)

{

       try

       {

             var guidProject = new Guid(projUid);

             ProjectDataSet dsProject = Project.ReadProject(guidProject, DataStoreEnum.WorkingStore);

             Guid? guidSession = dsProject.Project[0].PROJ_SESSION_UID;

 

             return guidSession.HasValue;

       }

       catch (Exception) {}

 

       return false;

}

En la función usamos la propiedad (Project) la cual deberíamos tener ya inicializada y que representa el servicio “Project.asmx

Puedes usar un inicializador similar al siguiente:

private void InitPs2010Helper(string urlInstPs, ICredentials credentials)

{

    this.Project = new Project();

    this.CustomFields = new CustomFields();

    this.LookupTable = new LookupTable();

    this.QueueSystem = new QueueSystem();

 

    this.Project.Credentials =

        this.CustomFields.Credentials =

        this.LookupTable.Credentials =

        this.QueueSystem.Credentials =

            credentials;

 

    this.Project.Url = string.Format("{0}/_vti_bin/PSI/Project.asmx", urlInstPs);

    this.CustomFields.Url = string.Format("{0}/_vti_bin/PSI/CustomFields.asmx", urlInstPs);

    this.LookupTable.Url = string.Format("{0}/_vti_bin/PSI/LookupTable.asmx", urlInstPs);

    this.QueueSystem.Url = string.Format("{0}/_vti_bin/PSI/QueueSystem.asmx", urlInstPs);

}

10 de diciembre de 2014

Error actualizando un WebPart: A feature with ID has already been installed in this farm. Use the force attribute to explicitly re-install the feature

 

Al intentar actualizar una solución (WSP) que contenía un WebPart me da el siguiente error:

A feature with ID has already been installed in this farm. Use the force attribute to explicitly re-install the feature.”

Solución:

Para solucionarlo:

  • En Visual Studio, ir al proyecto que contiene la característica (feature).
  • Abrir la feature en cuestión.
  • Clic en la pestaña “Manifiesto”, el cual nos mostrará el XML correspondiente al feature.
  • Agregar el atributo AlwaysForceInstall="TRUE".

Debe quedar algo similar a lo siguiente:

<Feature xmlns="http://schemas.microsoft.com/sharepoint/" Title="SadeArtefact" AlwaysForceInstall="TRUE" Id="45204110-acfc-4b0d-8884-d3a8711e3a21" Scope="Site">
  <ElementManifests>
    <ElementManifest Location="SadeInteractiveViewBacklogIniciativas\Elements.xml" />
  </ElementManifests>
</Feature>

 

Y con esto todo listo!!!

28 de noviembre de 2014

Project Server. Nivelación de Recursos

Este es un tema que tuve que investigar recientemente, son esas labores que haces muy de vez en cuando y que con el paso del tiempo caen en el olvido, por eso aprovecho esta entrada para anotar algunas cuestiones.

  • En el proceso de planificación, la nivelación de recursos resuelve la sobre-asignación de los recursos mediante el retraso de una tarea hasta que el recurso asignado está disponible para trabajar con él.

Ejemplo: A Luis se le asignan tres tareas con una duración de 8 horas cada una. Las tareas no tienen ni dependencias ni restricciones. Sin la nivelación de recursos, estas tareas están programadas para comenzar en el mismo día. Por tanto Luis está sobre-asignado ya que debe trabajar 32 horas en el mismo día para poder finalizar las tres tareas. Si usamos la opción de Nivelación de Recursos, éstas tareas se ordenaran para que comiencen una después de la otra.

Problemas al desplegar una solución (WSP) en SharePoint 2010

Problema o Error:

Recientemente, después de haber desarrollado una solución SharePoint (wsp), fuimos al servidor SP y la instalamos, para ello usamos el comando PowerShell siguiente:

Add-SPSolution –LiteralPath "C:\Solutions\MySolution1.wsp"

Hasta aquí todo bien, posteriormente quisimos desplegar dicha solución:

Install-SPSolution -Identity "MySolution1.wsp" –WebApplication http://ServerSpApp1.com/ –GACDeployment

El problemas era que se quedaba atascada indefinidamente en el estado “desplegando” (Deploying)… tal y como muestra la imagen:

image

 

Solución:

  1. Para solucionarlo reiniciamos el servicio “SharePoint Administration Service” en cada uno de los servidores de la granja.
  2. Cancelar el trabajo de despliegue.
  3. Intentar nuevamente el despliegue de la solución.

Nota: Este problema puede producirse también, cuando alguno de los servidores de la granja no tiene arrancado el servicio “SharePoint Administration Service”.

17 de octubre de 2014

Project Server–Obtener la etapa actual de un proyecto.

El tip de hoy es muy simple:

En Project Server 2013 si queremos recuperar (mediante T-SQL) el nombre de la etapa del flujo de trabajo en que se encuentra un proyecto, podemos declarar y usar la siguiente función que atacará la base de datos de Project Server (ProjectWebApp).

-- ============================================= 

-- Description:   Función que devuelve el stage actual de un proyecto

-- =============================================

CREATE FUNCTION dbo.fn_GetStageName

(

      @ProjectUID VARCHAR(50)

)

RETURNS VARCHAR(50)

AS

BEGIN

      DECLARE @ResultVar VARCHAR(50)

     

      SELECT

            @ResultVar = STAGE_NAME

      FROM

            ProjectWebApp.pub.MSP_WORKFLOW_STATUS_VIEW

      WHERE

            PROJ_UID = @ProjectUID

            AND STAGE_STATUS = 1   

           

      RETURN @ResultVar

END

Esto es todo!!!

8 de octubre de 2014

Error al agregar Web Part – Tipo no registrado como seguro

 

Al intentar agregar un Web Part a una página de SharePoint me da el siguiente error:

A Web Part or Web Form Control on this Page cannot be displayed or imported. The type could not be found or it is not registered as safe.”

 

Causa:

Después de investigar un poco, vimos que el problema estaba en que los tipos no estaban “sincronizados”.

Al desarrollar el Web Part con Visual Studio, se modificó el nombre de la clase, pero NO fue modificado en todos los archivos, y aunque no da error al compilar o desplegar; sí que da problemas al intentar agregar el Web Part en una página.

 

Solución:

Para solucionarlo debemos revisar los siguientes archivos de nuestro proyecto y cerciorarnos de que en todos usemos el mismo nombre correspondiente al tipo de la clase:

  • MiWebPart.webpart
  • MiWebPart.ascx
  • MiWebPart.ascx.cs
  • SharePointProjectItem.spdata (Este archivo normalmente está oculto en el proyecto, debemos marcar la opción de mostrar todos los archivos)

Ejemplo:

Si en nuestro archivo (MiWebPart.ascx.cs) usamos como nombre de clase (MiWebPartHolaMundo)

 

public partial class MiWebPartHolaMundo: WebPart

 

Entonces debemos revisar el resto de archivos para verificar que el tipo que usamos es (MiWebPartHolaMundo).

21 de agosto de 2014

Project Server 2010. Obtener valores de una lista SharePoint filtrada por proyecto

Recientemente me solicitaron una consulta con las siguientes premisas / condiciones: Dada una lista de SharePoint (ListaDePruebas), que se usa para almacenar ciertos valores (metadatos) de los distintos proyectos, se necesita recuperar dichos metadatos pero filtrados para un único proyecto.

Al final no deja de ser una lista genérica de SharePoint por lo que creamos un procedimiento almacenado como el siguiente:

CREATE PROCEDURE dbo.STPROC_GetInfoByList_ListaDePruebas

      @ProjectUID NVARCHAR(50) = NULL

AS

BEGIN

      DECLARE @ListId AS VARCHAR(50) = dbo.fnIng_GetListId('ListaDePruebas')

 

      SELECT

            UD.nvarchar3 AS ProjectUID,

            UD.bit1 AS EsParicipante,         

            UD.int1 AS AreaId,

            UDJ.tp_Id AS UserId,

            dbo.fnIng_GetUserName(UDJ.tp_Id) AS UserName,

            dbo.fnIng_GetUserEmail(UDJ.tp_Id) AS UserEmail

      FROM

            UserData UD

            LEFT JOIN UserDataJunctions UDJ

                  ON UDJ.tp_SourceListId = @ListId AND UDJ.tp_DocId = UD.tp_DocId

      WHERE

            UD.tp_ListId = @ListId

            AND UD.nvarchar3 = @ProjectUID

      ORDER BY

            UD.int1    

END

 

En el procedimiento almacenado hacemos uso de 2 funciones escalares que ya tenemos previamente desarrolladas y que no viene al caso explicar en este Tip:

dbo.fnIng_GetUserName: Dado el identificador del usuario, devuelve el nombre completo del mismo.

dbo.fnIng_GetUserEmail: Dado el identificador del usuario, devuelve el mail.

8 de agosto de 2014

Project Server 2013. Obtener valores Custom Field que permiten selecciones múltiples

Project Server 2013 ha modificado la estructura de base de datos de sus instancias, de las 4 bases de datos que existían en la versión PS 2010, ahora (PS 2013) se han consolidado en solo una.

Con esta evolución, han cambiado muchas cosas, una de ellas es la forma de recuperar los valores de un campo de empresa (Custom Field) que permiten selecciones múltiples.

En PS 2013 tendríamos que usar una consulta parecida a la siguiente:

DECLARE @CustomFieldUID VARCHAR(50) = 'ca88c587-72b7-4168-9010-1d2eaf344a62'

DECLARE @ProjectUID VARCHAR(50) = 'D4DFEE41-13AD-4C8C-A326-0A873D036A31'

SELECT

                CFA.EntityUID AS ProjectUID, P.ProjectName,             

                CFA.LookupMemberUID, LT.MemberValue AS ListItemValue

FROM        

                diag.dbo_MSP_EpmCustomFieldAssociation CFA

                LEFT JOIN dbo.[MSPLT_{NombreCampoEmpresa}_UserView] LT ON CFA.LookupMemberUID = LT.LookupMemberUID

                INNER JOIN dbo.MSP_EpmProject_UserView P ON CFA.EntityUID = p.ProjectUID

WHERE

                CFA.CustomFieldTypeUID = @CustomFieldUID

                AND CFA.EntityUID = @ProjectUID

 

Donde:

@CustomFieldUID: Identificador del campo de empresa (Custom Field) que permite selecciones múltiples y que deseamos recuperar.

@ProjectUID: Identificador del proyecto para el cual queremos recuperar los valores seleccionados.

{NombreCampoEmpresa}: Nombre del campo de empresa (Custom Field) que permite selecciones múltiples y que deseamos recuperar.

24 de julio de 2014

Como recuperar los mensajes dado un Identificador de Correlación

Recientemente se me presentó un problema en una granja SharePoint 2013, dado un error no controlado se mostraba la típica ventana genérica de error donde el único dato concreto es el Identificador de Correlación.

Para encontrar más detalles sobre el error fuimos al fichero log del primer servidor de la granja, y no encontramos el identificador; en lugar de ir probando suerte por los distintos servidores, decidimos usar el comando PowerShell que adjunto:

 

cls

If ((Get-PSSnapIn -Name Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue) -eq $null )

{

    Add-PSSnapIn -Name Microsoft.SharePoint.PowerShell

}

 

$correlationId = "89AEA79C-2114-0092-5CAC-ED92D3D0F919"

$logFilePath = "C:\Temp\aaFarmSpLog.log"

 

Merge-SPLogFile –Path $logFilePath –Correlation $correlationId -Overwrite 

 

Con este comando, obtendremos un nuevo fichero de log que contiene únicamente las entradas con el Identificador de Correlación especificado, además el comando se encarga de buscar en los logs de todos los servidores de la granja.

Este nuevo fichero será mucho más liviano y por lo tanto mucho más fácil de manejar.

20 de junio de 2014

SharePoint 2013. Búsqueda, Páginas Relevantes

Existen muchos factores que influyen en la calidad de los resultados devueltos por el motor de búsqueda de SharePoint:

  • Diccionarios
  • Páginas relevantes
  • Páginas no autoritativas
  • Reglas de rastreo
  • Otras

Intentaré hablar un poco de estos factores, pero hoy solo me centraré en “paginas relevantes” y “páginas no autoritativas”. En particular como definirlas usando PowerShell.

 

cls

If ((Get-PSSnapIn -Name Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue) -eq $null )

{

    Add-PSSnapIn -Name Microsoft.SharePoint.PowerShell

}

 

# Nombre de la aplicación de Búsqueda

$appSSA = "BusquedaIngProd"

# Cuenta del Motor de Búsqueda

$ctaSearch = Get-SPEnterpriseSearchOwner -Level ssa

 

Write-Host "La cuenta utilizada por el Motor de Búsqueda es: $ctaSearch" -foregroundcolor red -backgroundcolor yellow

 

# Crear 2 nuevas entradas en páginas relevantes

New-SPEnterpriseSearchQueryAuthority -Owner $ctaSearch -SearchApplication $appSSA -Url "https://MyWebTest/Vida" -Level 0

New-SPEnterpriseSearchQueryAuthority -Owner $ctaSearch -SearchApplication $appSSA -Url "https://MyWebTest/Hogar/Paginas/HogarSeguro.aspx" -Level 1

 

# Crear 1 nueva página como no-autoritativa

New-SPEnterpriseSearchQueryDemoted -Owner $ctaSearch -SearchApplication $appSSA -Url "https://MyWebTest/Paginas/Contacto.aspx"

 

Y eso es todo!!!