Impact sur les Feuilles de Temps de l’exportation/importation de projets dans Project Pro
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 :
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) :
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 :
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 :
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 :
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:
- Rappeler la Feuille de Temps
- 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 :
Si on exécute le script, on obtient le résultat attendu:
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 :
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