Nous sommes nombreux à avoir utilisé, avec Project 2003, la possibilité d’exporter et de réimporter un projet au format XML pour le “réparer” en cas de corruption de données après l’avoir supprimer de la base de données.

Certains d’entres vous utilisez peut-être encore cette solution avec Project 2007. Cependant, cela n’est plus aussi simple qu’avant et il est bon de connaitre les risques d’une telle manipulation avec Project 2007.

Tout d’abord, lorsque vous rencontrez un problème de corruption de projet, je vous recommande fortement d’utiliser au préalable les solutions suivantes:

  • Restaurer le Projet à partir d’une sauvegarde dans les paramètres du Serveur
  • Supprimer le projet de la base Published et le republier à partir de Project Pro
  • Modifier la valeur du champ PROJ_EXT_EDITED du projet dans la table MSP_PROJECTS de la table Published et le rouvrir dans Project Pro, puis le publier

Si toutefois aucune de ces solutions ne vous permet de réparer le projet, il vous reste la possibilité d’exporter le projet en XML et de le réimporter dans la base de données. Cependant, comme nous allons le voir, cette manipulation anodine avec Project 2003, provoque quelques effets de bords avec Project 2007, dans les Feuilles de Temps en particulier.

Création du projet:

Un projet TEST avec une tâche de 3 jours MyTask sur laquelle une ressource a été affectée est créé, sauvegardé et publié:

Dans la Feuille de Temps de la ressource, on observe l’apparition de la ligne d’affectation :

image

La ressource saisi 5h de Travail Réel pendant les 3 jours de la tâche puis soumet la Feuille de Temps, qui est automatiquement approuvée.

Cette Feuille de Temps est alors importée dans Mes Tâches puis les changements sont soumis, acceptés par le chef de projet et le projet est mis à jour.

Exportation et suppression du projet:

Constatant un dysfonctionnement du projet lié à une corruption de données binaires, le chef de projet décide de sauvegarder le projet au format XML à partir de Project 2007.

Puis, par l’intermédiaire des paramètres du serveur Project Server 2007, le chef de projet supprime le projet de toutes les bases de données.

ATTENTION :

La suppression complète d’un projet n’est pas sans effet sur la cohérence des données dans les bases de données Published et Reporting. En effet, les données de Feuilles de Temps et de Reporting font référence aux projets par l’intermédiaire de leur GUID. Lorsqu’un projet est supprimé, les liens entre les Feuilles de Temps existantes, les données de Reporting et le projet via son GUID sont cassés. De plus, les transactions en cours ou déjà effectuées, elles aussi basées sur le GUID du projet, deviennent orphelines et ne sont plus récupérables.

Dans la Feuille de Temps de la ressource, la ligne d’affectation apparait toujours (ligne orpheline) :

image

Si au premier coup d’œil on ne constate pas de différence flagrante avec l’état précédent, en observant de plus près, on s’aperçoit que le nom de la tâche n’apparait plus sous la forme d’un lien hypertexte. Ceci est normal car la ligne de Feuille de Temps est maintenant orpheline et n’est plus liée à une tâche existante (page Détail de la Tâche).

Voici un script SQL qui donne la liste des GUID manquants entre les Feuilles de Temps et le Travail Réel de la base de Reporting:

#############################################################################

IF OBJECT_ID(N'TEMPDB..#TIMESHEETTABLE',N'U') IS NOT NULL

DROP TABLE #TIMESHEETTABLE

 

IF OBJECT_ID(N'TEMPDB..#ACTUALSTABLE',N'U') IS NOT NULL

DROP TABLE #ACTUALSTABLE

 

IF OBJECT_ID(N'TEMPDB..#DIFFTS_PWA',N'U') IS NOT NULL

DROP TABLE #DIFFTS_PWA

 

USE PROJECTSERVER_PUBLISHED

SELECT MTL.TS_LINE_CACHED_PROJ_NAME,MTK.TASK_NAME, MR.RES_NAME, MTL.ASSN_UID, MTA.TS_ACT_START_DATE, MTA.TS_ACT_FINISH_DATE, MTA.TS_ACT_VALUE/60000 AS 'TS_ACT_VALUE', MTA.TS_ACT_PLAN_VALUE/60000 AS 'TS_ACT_PLAN_VALUE', MT.TS_STATUS_ENUM, MTL.TS_LINE_STATUS, MT.TS_UID

INTO #TIMESHEETTABLE

FROM MSP_TIMESHEET_LINES MTL

INNER JOIN MSP_TIMESHEET_ACTUALS MTA

ON MTL.TS_LINE_UID=MTA.TS_LINE_UID

AND MTL.TS_LINE_STATUS=3

INNER JOIN MSP_ASSIGNMENTS MA

ON MTL.ASSN_UID=MA.ASSN_UID

INNER JOIN MSP_RESOURCES MR

ON MA.RES_UID=MR.RES_UID

INNER JOIN MSP_TIMESHEETS MT

ON MTL.TS_UID=MT.TS_UID --AND MT.TS_STATUS_ENUM=3 AND MTL.TS_LINE_STATUS=3

INNER JOIN MSP_TASKS_SAVED MTK

ON MTL.TASK_UID=MTK.TASK_UID

 

USE PROJECTSERVER_REPORTING

SELECT MABD.ASSIGNMENTUID, MR.RESOURCENAME, MABD.TIMEBYDAY, MABD.PROJECTUID, MP.PROJECTNAME, MABD.TASKUID, MT.TASKNAME, MABD.ASSIGNMENTWORK, MABD.ASSIGNMENTACTUALWORK

INTO #ACTUALSTABLE

FROM MSP_EPMASSIGNMENTBYDAY MABD

INNER JOIN MSP_EPMPROJECT MP

ON MABD.PROJECTUID=MP.PROJECTUID

INNER JOIN MSP_EPMTASK MT

ON MABD.TASKUID=MT.TASKUID

INNER JOIN MSP_EPMASSIGNMENT MA

ON MABD.ASSIGNMENTUID=MA.ASSIGNMENTUID

INNER JOIN MSP_EPMRESOURCE MR

ON MA.RESOURCEUID=MR.RESOURCEUID

 

SELECT ISNULL(AC.RESOURCENAME,TS.RES_NAME) AS RESOURCENAME, ISNULL(AC.PROJECTNAME,TS.TS_LINE_CACHED_PROJ_NAME)AS PROJECTNAME, ISNULL(AC.TASKNAME, TS.TASK_NAME) AS TASKNAME, ISNULL(AC.TIMEBYDAY,TS.TS_ACT_START_DATE) AS TIMEBYDAY, AC.ASSIGNMENTACTUALWORK AS ASSIGNMENTACTUALWORK, TS.TS_ACT_VALUE AS TIMESHEETACTUALWORK, TS_STATUS_ENUM, TS_LINE_STATUS, TS_UID AS TIMESHEETUID

INTO #DIFFTS_PWA

FROM #ACTUALSTABLE AC

FULL OUTER JOIN #TIMESHEETTABLE TS

ON AC.ASSIGNMENTUID=TS.ASSN_UID

AND TS.TS_ACT_START_DATE=AC.TIMEBYDAY

AND AC.ASSIGNMENTWORK>0

 

SELECT RESOURCENAME, PROJECTNAME, TASKNAME, TIMEBYDAY, ASSIGNMENTACTUALWORK, TIMESHEETACTUALWORK, TIMESHEETUID

FROM #DIFFTS_PWA

WHERE (TIMESHEETACTUALWORK IS NULL AND ASSIGNMENTACTUALWORK > 0.01)

OR (ASSIGNMENTACTUALWORK IS NULL AND TIMESHEETACTUALWORK > 0.01)

OR (ABS(TIMESHEETACTUALWORK - ASSIGNMENTACTUALWORK) > 0.01)

AND TS_STATUS_ENUM=3

ORDER BY RESOURCENAME

 

DROP TABLE #TIMESHEETTABLE

DROP TABLE #ACTUALSTABLE

DROP TABLE #DIFFTS_PWA

#############################################################################

Si on exécute ce script, on obtient dans le cas présent, le résultat suivant :

image

On voit ici que les valeurs de Travail Réel sont toujours présentes dans la base de Reporting mais ne correspondent plus à rien dans la Feuille de Temps.

Importation et publication du projet:

Dans Project Pro, le chef de projet ouvre le fichier XML et republie le projet dans la base de données Project Server.

Dans la Feuille de Temps de la ressource, on observe l’apparition d’une nouvelle ligne d’affectation :

image

Il est intéressant de constater que ni l’une ni l’autre des deux lignes ne possède de lien hypertexte. En effet, lorsqu’un projet (ou une nouvelle affectation) est publié, la ligne n’est pas automatiquement insérée dans la Feuille de Temps. Elle apparait, mais cela est dû à l’exécution d’une procédure stockée (MSP_WEB_SP_QRY_GetAssnToAddToTimesheet ) qui permet de retourner la liste des affectations qui peuvent être insérées (mais ne le sont pas encore) dans la Feuille de Temps au moment de son chargement.

Si on exécute le script, on obtient dans le cas présent, le résultat suivant :

image

On constate effectivement que les valeurs de Travail Réel sont toujours dans la base de Reporting mais n’existent pas encore dans la Feuille de Temps. Il n’y a pas encore d’enregistrement dans la table MSP_TIMESHEET_LINES pour le projet publié.

Resynchroniser la Feuille de Temps

Pour resynchroniser les données, il faut:

  1. Rappeler la Feuille de Temps
  2. Soumettre la Feuille de Temps

A partir de là, les informations d’affectations retournées par la procédure stockée MSP_WEB_SP_QRY_GetAssnToAddToTimesheet sont intégrées dans la table MSP_TIMESHEET_LINES.

Lorsque la ressource ouvre à nouveau sa Feuille de Temps, elle peut observer le changement :

image

Si on exécute le script, on obtient le résultat attendu:

image

Les données de Feuille de Temps et de la base Reporting sont à nouveau synchronisées.

Ce point est très important car cela va permettre, lors de la mise à jour du Cube OLAP, de faire en sorte que les données intégrées dans le Cube soient bien celles du projet importé et non celles du projet supprimé.

Supprimer les lignes orphelines:

Il existe deux solutions pour supprimer les lignes orphelines dans la Feuille de Temps:

  • Rappeler la Feuille de Temps, la supprimer, la recréer
  • Utiliser le script suivant :

#############################################################################

SELECT TL.TS_LINE_UID, TL.TASK_UID, TL.PROJ_UID, TL.TS_LINE_CACHED_PROJ_NAME, TL.TS_LINE_CACHED_ASSIGN_NAME, TL.TS_LINE_VALIDATION_TYPE, MP.PROJ_NAME

INTO #TSLINESCOMPARISON

FROM MSP_TIMESHEET_LINES TL

LEFT JOIN MSP_PROJECTS MP

ON TL.PROJ_UID=MP.PROJ_UID

ORDER BY TL.PROJ_UID

 

SELECT TS_LINE_UID

INTO #LISTOFLINEUIDFORDELETEDTSLINES

FROM #TSLINESCOMPARISON

WHERE PROJ_NAME IS NULL AND TS_LINE_VALIDATION_TYPE>0

 

SELECT * FROM MSP_TIMESHEET_LINES TL

INNER JOIN #LISTOFLINEUIDFORDELETEDTSLINES LDL

ON TL.TS_LINE_UID=LDL.TS_LINE_UID

 

DECLARE DELETE_TSLINE CURSOR FOR

SELECT TL.TS_LINE_UID FROM MSP_TIMESHEET_LINES TL

INNER JOIN #LISTOFLINEUIDFORDELETEDTSLINES LDL

ON TL.TS_LINE_UID=LDL.TS_LINE_UID

 

OPEN DELETE_TSLINE

DECLARE @TS_LINE_UID UID

 

FETCH NEXT FROM DELETE_TSLINE INTO @TS_LINE_UID

 

       WHILE @@FETCH_STATUS = 0

BEGIN

       EXEC MSP_WEB_SP_QRY_DELETETIMESHEETLINE  @TS_LINE_UID 

       FETCH NEXT FROM DELETE_TSLINE INTO @TS_LINE_UID

END

 

DEALLOCATE DELETE_TSLINE

DROP TABLE #LISTOFLINEUIDFORDELETEDTSLINES

DROP TABLE #TSLINESCOMPARISON

#############################################################################

Après l’avoir exécuter, dans la Feuille de Temps, la ligne orpheline a été supprimée :

image

Conclusion:

Encore une fois, je ne recommande d’utiliser cette solution que lorsque toutes les autres possibilités ont été testées sans succès.

 

Marc Biarnès