Index: openacs-4/packages/project-manager/project-manager.info
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/project-manager.info,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/project-manager.info 29 Apr 2005 17:43:36 -0000 1.1
@@ -0,0 +1,52 @@
+
+
+
+
+ Project Manager
+ Project Managers
+ f
+ f
+
+
+ Jade Rubick
+ Project management tool for OpenACS
+ 2005-01-13
+ Integrated Bakery Resources
+ Track tasks, estimates and actual progress for a project. See the <a href="http://openacs.org/projects/dotwrk/project_management/">project page</a> for more information.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: openacs-4/packages/project-manager/catalog/project-manager.de_DE.ISO-8859-1.xml
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/catalog/project-manager.de_DE.ISO-8859-1.xml,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/catalog/project-manager.de_DE.ISO-8859-1.xml 29 Apr 2005 17:43:36 -0000 1.1
@@ -0,0 +1,160 @@
+
+
+
+ Aktion
+ Aktionen
+ Hinzuf�gen
+ Subprojekt hinzuf�gen
+ Beauftragte
+ Durchschnitt
+ abbrechen, nicht l�schen
+ Kategorien
+ Code
+ Kommentar:
+ Kommentar
+ abgeschlossen:
+ Kunde
+ Datum
+ Daten
+ Abgabetermin:
+ Vordefinierte Rollen
+ L�schen
+ Abh�ngigkeiten
+ Abh�ngigkeit:
+ Abh�ngigkeitstypen
+ Beschreibung
+ Beschreibung:
+ Erledigt.
+ Fr�hestes Ende
+ Fr�hester Beginn
+ �ndern
+ Beauftragte �ndern
+ Kategorien �ndern
+ Fehler
+ Ziel
+ Stunden
+ Std.
+ Schl�ssel
+ Sp�testes Ende
+ Sp�tester Beginn
+ Aufwandserfassung Eintrag:
+ Aufwandserfassung
+ Aufwandserfassung Integration
+ . Der Projektmanager erfordert es, zumindestens eine Instanz der Aufwandserfassung zu installieren und zu "mounten", da das Package die Aufwandserfassung dazu nutzt, Zeit und andere Aufw�nde gegen�ber den Projekten und Aufgaben zu erfassen. Sie k�nnen aber auch variierende Integrationslevels mit der Aufwandserfassung definieren. In dieser Sektion richten Sie ein, welche Instanz der Aufwandserfassung mit dem Projektmanager voll integriert sein soll, so dass neue Projektmanager Projekte in der Aufwandserfassungsinstanz erscheinen.
+ . Der Projektmanager erfordert es, zumindestens eine Instanz der Aufwandserfassung zu installieren und zu "mounten", da das Package die Aufwandserfassung dazu nutzt, Zeit und andere Aufw�nde gegen�ber den Projekten und Aufgaben zu erfassen. Sie k�nnen aber auch variierende Integrationslevels mit der Aufwandserfassung definieren. In dieser Sektion richten Sie ein, welche Instanz der Aufwandserfassung mit dem Projektmanager voll integriert sein soll, so dass neue Projektmanager Projekte in der Aufwandserfassungsinstanz erscheinen.
+ Nachdem sie dies getan haben, k�nnen Sie zur vorherigen Seite zur�ckgehen, sie neu laden und dann Studen erfassen oder bereits erfasste Stunden ver�ndern.
+ M�chten Sie jetzt mit diesen URLS synchronisieren?
+ Sind Sie sich sicher, dass sie diesen Prozess l�schen wollen: %one_line%
+ Sind Sie sich sicher, dass Sie diese %task_term_lower% l�schen wollen?
+ (Seien Sie geduldig, es dauert einige Zeit. Sie k�nnen die log files lesen, um zu sehen was geschieht.)
+ Synchronsierung starten
+ Klicken Sie auf eines der folgenden Wahlm�glichkeiten, um den Setup zu starten:
+ Abgeschlossen: %task_info.percent_complete%%
+ Datum: %entries.time_stamp_pretty%
+ Ist von einer anderen %task_term_lower% abh�ngig
+ Geben Sie 100% ein, um diese %task_term_lower% zu schliessen, oder weniger um anzulegen.
+ Verbliebende Stunden: %task_info.hours_remaining%
+ @import "%package_url%style-logger.css"; @import "%package_url%style.css";
+ Die Aufwandserfassung ist ein Package, das es Ihnen erlaubt, die in dem Projekt geleisteten Stunden, Kosten etc. zu erfassen.
+ Die Aufwandserfassung ist ein Package, das es Ihnen erlaubt, die in dem Projekt geleisteten Stunden, Kosten etc. zu erfassen.
+ %num.rownum%
+ (nicht aktuell, w�hlen Sie die live Version aus
+ Sobald Sie INstanzen der Aufwandserfassung in den Projektmanager integriert haben, k�nnten Sie viele �ltere Projekte in Ihrem Projektmanager haben, die nicht mit der Aufwandserfassung synchronisiert sind. Diese Seite erlaubt es Ihnen, �ltere Projekte im Projektmanager mit der Aufwandserfassung zu synchronisieren, so dass alle korrekt mit der Instanz verbunden sind. <br>[Originalanmerkung: This does not add in logger projects to project-manager (although someone can certainly add that functionality if they wish).]
+ Projekt: %entries.project_name%
+ %project.actual_hours_completed% von %project.estimated_hours_total%
+ Projekte k�nnen gem�� unterschiedlicher Kategorieb�ume kategorisiert werden. Die serlaubt es Ihnen, Ihre Projekte auf verschiedene Arten zu kategorisieren. Diese Abschnitt richtet Ihre Kategorien ein und erlaubt Ihnen, diese zu Projekten zu verkn�pfen. [Engl. Originalanmerkung: Currently, there is a bug in the categories package that prevents the context bar at the top of the screen from returning you to the project-manager pages.]
+ e-Mail an Beaufragte schicken?
+ gem�� den Aufgabenzuteilungen setzen
+ Setup Integration mit der Aufwandserfassung
+ �berspringen der Hinzuf�gung von Abh�ngigkeiten
+ Verbliebene Zeit: %task_info.slack_time%
+ Verbliebene Zeit: %task_info.slack_time%
+ %task_info.estimated_hours_work_min% - %task_info.estimated_hours_work_max% gesch�tzte Stunden
+ %task_info.percent_complete%% abgeschlossen
+ %task_term% die von %task_term% abh�ngen
+ %task_term% die von %task_term% abh�ngen
+ %task_term% von der diese abh�ngt.
+ %task_term% von der diese abh�ngt.
+ Der Administrator muss
+ Das Datenmodell ber�cksichtigt vordefinierte Rollen, obwohl es zurzeit nicht genutzt wird. Die zeigt, welche vordefinierten Rollen in der Datenbank gespeichert sind. Zurzeit noch nicht implementiert.
+ Diese Parameter erlauben es Ihnen, t�gliche Erinnerungsmails aufzusetzen, die anzuzeigenden Felder in einer Projekt�bersicht zu ver�ndern etc. Sehr empfehlenswert, wenn Sie den Projektmanager aufsetzen!
+ Die Rollen, die einzelne User in einem Projekt annehmen k�nnen , wie Manager, Ansprechpartner f�r den Techn. Support etc. Zurzeit k�nnen diese leider nur direkt in der Datenbank ver�ndert werden.
+ Es existieren keine passenden erfassten Aufw�nde
+ Es existiert ein Datenmodell f�r Workgroups, aber dieses ist nicht Teil des User Interfaces. Zeigt was alles in der Datenbank ist (zurzeit nichts!)
+ [Originalanmerkung: There is currently a bug in this page where it will not allow you to remove values. You will have to do that through the parameters section.]
+ Diese Seite erlaubt es Ihnen, die Abgabetermine aller Ihrer Projekte in Ihrer Installation zu aktualisieren. Das wird eine Weile dauern.
+ Diese Seite wird Ihnen irgendwann einmal erlauben, Ihre Stunden zu mehreren Aufgaben auf einmal zu erfassen.
+ Zu diesem Prozess %task_term_lower%. Abh�ngigkeiten beschreiben die Reihenfolge, in der die einzelnen Teile abgeschlossen werden m�ssen, z.B. "die Bretter m�ssen geliefert werden bevor die Konstruktion beginnen kann". Es ist wichtig, Abh�ngigkeiten einzugeben, da es dem System erlaubt, Terminpl�ne automatisch zu erzeugen.
+ Unbekannte Gruppe nach Spalte %group_by%
+ Diesen Prozess benutzen: %use_link;noquote%
+ User: %entries.user_chunk;noquote%
+ G�ltige Status Codes, z.B. "Offen" und "Abgeschlossen"
+ Woche: %entries.time_stamp_week%
+ Wenn implementiert, erlaubt diese Seite Ihnen, die Beschreibung von unterschiedlichen Abh�ngigkeiten (wie "endet vor dem Start von ..) anzusehen und zu ver�ndern. Zurzeit wird lediglich die Abh�ngigkeit "endet vor dem Start von" genutzt, weswegen diese nicht in der UI erscheint.
+ Optional k�nnen Sie die gearbeitete Zeit auch hier erfassen.
+ Sie k�nnen eine %task_term_lower% einf�gen, die vor dieser %task_term_lower% abgeschlossen sein muss
+ Optional k�nnen Sie ein fixen Abgabetermin eingeben
+ Sie m�ssen eine Instanz der Aufwandserfassung w�hlen, in der die prim�re Erfassung in dem Projektmanager geschehen soll. Diese ist eng mit dem Projektmanager verbunden, so dass Sie sich Berichte zu einem Projekt etc. ansehen k�nnen.
+ Sie m�ssen hier eine Zahl eingeben (sch�tzen Sie)
+ Max.:
+ Min.:
+ name
+ %project_term%
+ Kein User Interface
+ Jetzt
+ Ein Prozess
+ laufend
+ Reihenfolge
+ Seite)
+ Parameter
+ Prozess Aufgaben:
+ Prozess Aufgaben
+ Prozesse
+ Projekt:
+ Projektkategorien
+ Projektinformation
+ Projektsuche:
+ %project_term;noquote%e
+ %project_term%s
+ Vorausschau
+ Projekte
+ Verbundene %task_term%
+ Mich selber entfernen
+ Rollen
+ Suche:
+ Suche:
+ Abschnitt
+ Prozess ausw�hlen:
+ Set up
+ Diese Aufgabe �berspringen?
+ Verbliebene Zeit:
+ Verbliebene Zeit: n/a
+ Beginn
+ Statustyp
+ Thema:
+ Subprojekte
+ Zwischensumme
+ Zwischensumme Durchschnitt
+ Synchronisieren
+ Aufgabe
+ Aufgaben�nderung
+ Aufgabe, erfasste Stunden
+ %task_term%s
+ AUFGABEN
+ Aufgaben
+ Zeit:
+ Gesamt
+ Gesamte ben�tigte Arbeitszeit:
+ Alle aktualisieren
+ User
+ Anzusehende User
+ Variablen
+ Ansicht
+ Optionen ansehen
+ Projekt�nderungen ansehen
+ Aufgaben�nderungen ansehen
+ Arbeit
+ Notwendige Arbeit:
+ Arbeitsgruppen
+ Sie k�nnen nun hinzuf�gen
+
Index: openacs-4/packages/project-manager/catalog/project-manager.en_US.ISO-8859-1.xml
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/catalog/project-manager.en_US.ISO-8859-1.xml,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/catalog/project-manager.en_US.ISO-8859-1.xml 29 Apr 2005 17:43:36 -0000 1.1
@@ -0,0 +1,214 @@
+
+
+
+ Action
+ Actions
+ Add
+ Add subproject
+ Assignees
+ Average
+ Cancel, do not delete
+ Categories
+ Code
+ Comment:
+ Comments
+ Complete:
+ Customer
+ Date
+ Dates
+ Deadline:
+ Default roles
+ Delete
+ dependencies
+ Dependency:
+ Dependency types
+ Description
+ Description:
+ Done.
+ Earliest finish
+ Earliest start
+ Edit
+ Edit assignees
+ Edit categories
+ Error
+ Goal
+ hours
+ hrs
+ Key
+ Latest finish
+ Latest start
+ Log entry:
+ Logger
+ Logger integration
+ . Project manager requires you to
+ install and mount at least one instance of logger, because it
+ uses logger to log time and other variables against projects
+ and tasks. However, you can have varying levels of integration
+ with logger. This section sets up which logger instances you
+ want to be fully integrated with project-manager, so that new
+ project-manager projects appear in the logger instance.
+ . Project manager requires you to
+ install and mount at least one instance of logger, because it
+ uses logger to log time and other variables against projects
+ and tasks. However, you can have varying levels of integration
+ with logger. This section sets up which logger instances you
+ want to be fully integrated with project-manager, so that new
+ project-manager projects appear in the logger instance.
+ After they have done this, you can go back to the previous page,
+ refresh it, and then add and edit logged hours.
+ Are you ready to sync with these URLs?
+ Are you sure you want to delete this process: %one_line%
+ Are you sure you'd like to delete these %task_term_lower%s?
+ (be patient,
+ this takes a long time, you can read the log files to see what's
+ happening if you like.)
+ Begin synchronization
+ Click on one of the following items to set it up:
+ Complete: %task_info.percent_complete%%
+ Date: %entries.time_stamp_pretty%
+ depends on another %task_term_lower%
+ Enter 100% to close the %task_term_lower%, or less
+ to open it.
+ Hours remaining: %task_info.hours_remaining%
+ @import "%package_url%style-logger.css";
+ @import "%package_url%style.css";
+ Logger is a package that lets you log time, expenses, and
+ other
+ Logger is a package that lets you log time, expenses, and
+ other
+ %num.rownum%
+ (not current, select live version from the
+ Once you have chosen logger instances to be integrated
+ with project-manager, you may have a lot of older
+ project-manager projects that are not synchronized with
+ logger. This page lets you synchronize older project-manager
+ projects with logger, so that they are all linked in correctly
+ with that instance. This does not add in logger projects to
+ project-manager (although someone can certainly add that
+ functionality if they wish).
+ Project: %entries.project_name%
+ %project.actual_hours_completed% of %project.estimated_hours_total%
+ Projects can be categorized according to multiple 'trees'
+ of categories. What this means is you can have multiple ways
+ of categorizing your projects. This section sets up your
+ categories and allows you to link them to projects. Currently,
+ there is a bug in the categories package that prevents the
+ context bar at the top of the screen from returning you to the
+ project-manager pages.
+ Send email to assignees?
+ set according to task assignments
+ set up integration with logger
+ skip adding dependencies
+ Slack: %task_info.slack_time%
+ Slack time: %task_info.slack_time%
+ %task_info.estimated_hours_work_min% - %task_info.estimated_hours_work_max% hrs estimated
+ %task_info.percent_complete%% complete
+ %task_term%s depending on this %task_term%
+ %task_term%(s) depending on this %task_term%
+ %task_term%s this depends on.
+ %task_term%(s) this depends on.
+ The administrator needs to
+ The data model has a facility for default roles, although
+ it is not currently used at all. This shows what is in the
+ database for default roles. Currently unimplemented.
+ The parameters allow you to do things such as set up daily
+ reminder emails, change what fields are shown in the project
+ view and edit pages, and so on. Highly recommended if you're
+ setting up project-manager.
+ The roles people can take on projects and tasks, such as
+ manager, sales contact, tech support person, etc.. Currently,
+ can only be edited directly in the database.
+ There are no matching log entries
+ There is a data model for workgroups, but it is not a part
+ of the UI. Shows what is in the database (currently, nothing!)
+ There is currently a bug in this page where it will not allow you to
+ remove values. You will have to do that through the parameters section.
+ This page allows you to update the deadlines of all the
+ projects in your installation. It will take a while.
+ This page will eventually allow you to log hours against multiple
+tasks at once.
+ to these process
+%task_term_lower%s. Dependencies describe the order in which items must
+be completed. For example, "the boards must be delivered before
+construction can begin". Entering dependencies is important because it
+allows the system to automatically compute schedules. However, you can
+ Unknown group by column %group_by%
+ Use this process: %use_link;noquote%
+ User: %entries.user_chunk;noquote%
+ Valid status codes, for example, 'Open' and 'Closed'
+ Week: %entries.time_stamp_week%
+ When implemented, this page will allow you to view and
+ edit the descriptions given to various dependency types (such
+ as finish before start, etc..) Currently, the only dependency
+ used is finish before start, so it's not exposed in the UI
+ You can optionally log time worked here.
+ You may enter a %task_term_lower% that needs to
+ be completed before this %task_term_lower%
+ You may optionally enter a hard deadline
+ You must choose a logger instance to be the primary
+ logger linked in with project-manager. This is closely linked
+ in with project-manager, so you can view reports of a project, etc.
+ You must enter a number here (make your best
+ guess)
+ Max:
+ Min:
+ Name
+ %project_term%
+ No UI
+ Now
+ One process
+ Ongoing
+ Order
+ page)
+ Parameters
+ Process tasks:
+ process tasks
+ Processes
+ Project:
+ Project categories
+ Project information
+ Project Search:
+ %project_term;noquote%s
+ %project_term%s
+ Projection
+ Projects
+ Related %task_term%s
+ Remove myself
+ Roles
+ Search:
+ Search:
+ Section
+ Select process:
+ Set up
+ Skip this task?
+ Slack:
+ Slack: n/a
+ Start
+ Status types
+ Subject:
+ Subprojects
+ Subtotal
+ Subtotal Average
+ Sync
+ Task
+ task change
+ Task hours completed
+ %task_term%s
+ TASKS
+ Tasks
+ Time:
+ Total
+ Total work required:
+ Update all
+ User
+ Users to view
+ variables
+ View
+ View options
+ View project changes
+ View task changes
+ Work
+ Work required:
+ Workgroups
+ You may now add
+
Index: openacs-4/packages/project-manager/lib/process-instances-postgresql.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/lib/process-instances-postgresql.xql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/lib/process-instances-postgresql.xql 29 Apr 2005 17:43:36 -0000 1.1
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+ postgresql
+ 7.3
+
+
+
+
+ SELECT
+ i.name || ' (' || i.instance_id || ')' as name,
+ i.project_item_id as my_project_id,
+ i.instance_id,
+ pr.title as project_name
+ FROM
+ pm_process_instance i,
+ cr_items pi,
+ cr_revisions pr
+ WHERE
+ i.project_item_id = pi.item_id and
+ pi.live_revision = pr.revision_id and
+ i.instance_id in
+ (select
+ t.process_instance
+ from
+ pm_tasks_active t,
+ pm_task_status s
+ where
+ t.status = s.status_id and
+ t.process_instance is not null and
+ s.status_type = 'o')
+ ORDER BY
+ name
+
+
+
+
Index: openacs-4/packages/project-manager/lib/process-instances.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/lib/process-instances.adp,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/lib/process-instances.adp 29 Apr 2005 17:43:36 -0000 1.1
@@ -0,0 +1,10 @@
+
+
Index: openacs-4/packages/project-manager/lib/process-instances.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/lib/process-instances.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/lib/process-instances.tcl 29 Apr 2005 17:43:36 -0000 1.1
@@ -0,0 +1,29 @@
+#
+#
+# Displays a table of active process instances
+#
+# @author Jade Rubick (jader@bread.com)
+# @creation-date 2004-10-21
+# @arch-tag: 21a71f70-73cb-4152-9f1b-a32932ef2f9b
+# @cvs-id $Id: process-instances.tcl,v 1.1 2005/04/29 17:43:36 timoh Exp $
+
+foreach required_param {} {
+ if {![info exists $required_param]} {
+ return -code error "$required_param is a required parameter."
+ }
+}
+foreach optional_param {} {
+ if {![info exists $optional_param]} {
+ set $optional_param {}
+ }
+}
+
+# get open processes
+
+db_multirow -extend {url} instances instances { } {
+ set url [pm::process::url \
+ -process_instance_id $instance_id \
+ -project_item_id $my_project_id \
+ -fully_qualified_p "f"]
+
+}
Index: openacs-4/packages/project-manager/sql/oracle/project-manager-create.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/sql/oracle/project-manager-create.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/sql/oracle/project-manager-create.sql 29 Apr 2005 17:43:36 -0000 1.1
@@ -0,0 +1,12 @@
+--
+-- packages/project-manager/sql/postgresql/project-manager-create.sql
+--
+-- @author jade@bread.com
+-- @creation-date 2003-05-15
+-- @cvs-id $Id: project-manager-create.sql,v 1.1 2005/04/29 17:43:36 timoh Exp $
+--
+--
+
+@@ project-manager-table-create.sql
+@@ project-manager-functions-create.sql
+@@ project-manager-notifications-create.sql
Index: openacs-4/packages/project-manager/sql/oracle/project-manager-custom-create.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/sql/oracle/project-manager-custom-create.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/sql/oracle/project-manager-custom-create.sql 29 Apr 2005 17:43:36 -0000 1.1
@@ -0,0 +1,45 @@
+--
+-- packages/project-manager/sql/postgresql/project-manager-customize.sql
+--
+-- @author jader@bread.com
+-- @creation-date 2003-12-05
+--
+
+-- this file is used to add custom columns to the projects table.
+-- you can then customize the columns shown
+
+-- if you do set this up, you need to set the parameter in the admin
+-- UI, so that the add-edit page will know that there is custom code,
+-- You'll need to create an add-edit-custom page, filling in the skeleton there
+
+-- you should use the content_type__create_attribute procedure to add
+-- in columns so that the views are correctly recreated.
+
+-- PROJECTS
+
+-- example, using customer
+-- this is actually done in the table-create script
+
+-- this adds in the customer column. This is an example of how
+-- the custom columns are added in. I put this here as a reminder
+-- that other columns can be added in as well. These custom items
+-- are in the custom-create.sql script
+
+declare
+ attribute_id integer;
+begin
+ attribute_id := content_type.create_attribute (
+ content_type => 'pm_project',
+ attribute_name => 'customer_id',
+ datatype => 'integer',
+ pretty_name => 'Customer',
+ pretty_plural => 'Customers',
+ sort_order => null,
+ default_value => null,
+ column_spec => 'integer constraint pm_project_customer_fk references organizations'
+ );
+end;
+/
+
+show errors
+
Index: openacs-4/packages/project-manager/sql/oracle/project-manager-custom-drop.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/sql/oracle/project-manager-custom-drop.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/sql/oracle/project-manager-custom-drop.sql 29 Apr 2005 17:43:36 -0000 1.1
@@ -0,0 +1,12 @@
+-- packages/project-manager/sql/project-manager-drop.sql
+-- drop script
+--
+-- @author jade@bread.com
+-- @creation-date 2003-12-05
+-- @cvs-id $Id: project-manager-custom-drop.sql,v 1.1 2005/04/29 17:43:36 timoh Exp $
+--
+
+-- drop any custom tables here.
+
+select content_type__drop_attribute ('pm_project', 'customer_id', 't');
+
Index: openacs-4/packages/project-manager/sql/oracle/project-manager-drop.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/sql/oracle/project-manager-drop.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/sql/oracle/project-manager-drop.sql 29 Apr 2005 17:43:36 -0000 1.1
@@ -0,0 +1,212 @@
+-- packages/project-manager/sql/project-manager-drop.sql
+-- drop script
+--
+-- @author jade@bread.com
+-- @creation-date 2003-05-15
+-- @cvs-id $Id: project-manager-drop.sql,v 1.1 2005/04/29 17:43:36 timoh Exp $
+--
+
+--------
+-- TASKS
+--------
+
+\i project-manager-custom-drop.sql
+\i project-manager-notifications-drop.sql
+
+drop table pm_task_logger_proj_map;
+
+create function inline_0 ()
+returns integer as '
+declare
+ v_item RECORD;
+
+begin
+ for v_item in select
+ item_id
+ from
+ cr_items
+ where
+ content_type = ''pm_task''
+ LOOP
+ PERFORM pm_task__delete_task_item(v_item.item_id);
+ end loop;
+
+ return 0;
+end;
+' language 'plpgsql';
+
+select inline_0();
+drop function inline_0();
+
+-- unregister content_types from folder
+create function inline_0 ()
+returns integer as '
+declare
+ v_folder_id cr_folders.folder_id%TYPE;
+ v_item_id cr_items.item_id%TYPE;
+ v_item_cursor RECORD;
+begin
+
+ -- delete all contents of projects folder
+ FOR v_item_cursor IN
+ select
+ item_id
+ from
+ cr_items
+ where
+ content_type = ''pm_task''
+ LOOP
+ PERFORM pm_project__delete_task_item(v_item_cursor.item_id);
+ END LOOP;
+
+ -- this table must not hold reference to ''pm_tasks'' type
+ delete from cr_folder_type_map where content_type = ''pm_tasks'';
+
+ return 0;
+end;
+' language 'plpgsql';
+
+select inline_0();
+drop function inline_0();
+
+-- unregister content_types from folder
+create function inline_0 ()
+returns integer as '
+declare
+ v_folder_id cr_folders.folder_id%TYPE;
+ v_item_id cr_items.item_id%TYPE;
+ v_item_cursor RECORD;
+begin
+
+ -- delete all contents of projects folder
+ FOR v_item_cursor IN
+ select
+ item_id
+ from
+ cr_items
+ where
+ content_type = ''pm_project''
+ LOOP
+ PERFORM pm_project__delete_project_item(v_item_cursor.item_id);
+ END LOOP;
+
+ return 0;
+end;
+' language 'plpgsql';
+
+select inline_0();
+drop function inline_0();
+
+-- unregister content_types from folder
+create function inline_0 ()
+returns integer as '
+declare
+ v_folder_id cr_folders.folder_id%TYPE;
+ v_item_id cr_items.item_id%TYPE;
+ v_item_cursor RECORD;
+begin
+
+ FOR v_item_cursor IN
+ select folder_id from cr_folders where description=''Project Repository''
+ LOOP
+ PERFORM content_folder__unregister_content_type (
+ v_item_cursor.folder_id, -- folder_id
+ ''pm_project'', -- content_type
+ ''t'' -- include_subtypes
+ );
+ PERFORM content_folder__delete(v_item_cursor.folder_id);
+ END LOOP;
+
+ -- this table must not hold reference to ''pm_project'' type
+ delete from cr_folder_type_map where content_type = ''pm_project'';
+
+ return 0;
+end;
+' language 'plpgsql';
+
+select inline_0();
+drop function inline_0();
+
+
+-- task dependency types
+drop table pm_task_dependency_types cascade;
+drop table pm_task_dependency cascade;
+drop sequence pm_task_dependency_seq;
+drop sequence pm_tasks_number_seq;
+
+select content_type__drop_attribute ('pm_task', 'end_date', 't');
+select content_type__drop_attribute ('pm_task', 'percent_complete', 't');
+select content_type__drop_attribute ('pm_task', 'estimated_hours_work', 't');
+select content_type__drop_attribute ('pm_task', 'estimated_hours_work_min', 't');
+select content_type__drop_attribute ('pm_task', 'estimated_hours_work_max', 't');
+select content_type__drop_attribute ('pm_task', 'actual_hours_worked', 't');
+select content_type__drop_attribute ('pm_task', 'earliest_start', 't');
+select content_type__drop_attribute ('pm_task', 'earliest_finish', 't');
+select content_type__drop_attribute ('pm_task', 'latest_start', 't');
+select content_type__drop_attribute ('pm_task', 'latest_finish', 't');
+
+-------------
+-- WORKGROUPS
+-------------
+
+drop sequence pm_workgroup_seq;
+drop table pm_workgroup_parties;
+drop table pm_workgroup;
+
+------------
+-- PROCESSES
+------------
+
+drop sequence pm_process_seq;
+drop sequence pm_process_task_seq;
+drop sequence pm_process_task_dependency_seq;
+
+drop table pm_process_task_assignment;
+drop table pm_process_task_dependency;
+drop table pm_process_task;
+drop table pm_process;
+
+---------
+-- OTHERS
+---------
+drop table pm_default_roles;
+drop table pm_project_assignment;
+drop table pm_task_assignment;
+drop table pm_roles;
+drop sequence pm_role_seq;
+
+
+select drop_package('pm_task');
+
+
+-----------
+-- PROJECTS
+-----------
+
+--drop permissions
+delete from acs_permissions where object_id in (select project_id from pm_projects);
+
+
+-- drop package, which drops all functions created with define_function_args
+select drop_package('pm_project');
+
+--drop table
+drop table pm_projects cascade;
+
+drop sequence pm_project_status_seq;
+drop table pm_project_status cascade;
+
+
+
+drop sequence pm_task_status_seq;
+drop table pm_task_status cascade;
+
+drop table pm_tasks cascade;
+drop table pm_tasks_revisions cascade;
+
+select content_type__drop_type('pm_task', 't', 'f');
+
+select content_type__drop_type('pm_project', 't', 'f');
+
+-- note that the Project Repository folder is not deleted
+
Index: openacs-4/packages/project-manager/sql/oracle/project-manager-functions-create.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/sql/oracle/project-manager-functions-create.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/sql/oracle/project-manager-functions-create.sql 29 Apr 2005 17:43:36 -0000 1.1
@@ -0,0 +1,610 @@
+--
+-- packages/project-manager/sql/postgresql/project-manager-functions-create.sql
+--
+-- @author jade@bread.com, ncarroll@ee.usyd.edu.au
+-- @creation-date 2003-05-15
+-- @cvs-id $Id: project-manager-functions-create.sql,v 1.1 2005/04/29 17:43:36 timoh Exp $
+--
+--
+
+-- When we created the acs object type above, we specified a
+-- 'name_method'. This is the name of a function that will return the
+-- name of the object. This is a convention ensuring that all objects
+-- can be identified. Now we have to build that function. In this case,
+-- we'll return a field called title as the name.
+
+
+create or replace package pm_project as
+
+ function name ( p_pm_project_id in pm_projects.project_id%TYPE
+ ) return varchar2;
+
+ function new_root_folder (p_package_id in apm_packages.package_id%TYPE
+ ) return integer;
+
+ function get_root_folder (p_package_id in apm_packages.package_id%TYPE ,
+ p_create_if_not_present_p in char
+ ) return integer;
+
+ function new_project_item (
+ p_project_name in varchar2 ,
+ p_project_code in pm_projects.project_code%TYPE,
+ p_parent_id in integer ,
+ p_goal in pm_projects.goal%TYPE,
+ p_description in varchar2 ,
+ p_mime_type in varchar2 ,
+ p_planned_start_date in pm_projects.planned_start_date%TYPE ,
+ p_planned_end_date in pm_projects.planned_end_date%TYPE ,
+ p_actual_start_date in pm_projects.actual_start_date%TYPE ,
+ p_actual_end_date in pm_projects.actual_end_date%TYPE,
+ p_logger_project in pm_projects.logger_project%TYPE ,
+ p_ongoing_p in pm_projects.ongoing_p%TYPE ,
+ p_status_id in pm_projects.status_id%TYPE ,
+ p_customer_id in pm_projects.customer_id%TYPE ,
+ p_creation_date in date default sysdate,
+ p_creation_user in integer,
+ p_creation_ip in varchar2,
+ p_package_id in integer
+ ) return integer;
+
+ procedure delete_project_item ( p_project_id in pm_projects.project_id%TYPE);
+
+ function new_project_revision (
+ p_item_id in integer ,
+ p_project_name in varchar2 ,
+ p_project_code in pm_projects.project_code%TYPE,
+ p_parent_id in integer ,
+ p_goal in pm_projects.goal%TYPE,
+ p_description in varchar2 ,
+ p_planned_start_date in pm_projects.planned_start_date%TYPE ,
+ p_planned_end_date in pm_projects.planned_end_date%TYPE ,
+ p_actual_start_date in pm_projects.actual_start_date%TYPE ,
+ p_actual_end_date in pm_projects.actual_end_date%TYPE,
+ p_logger_project in pm_projects.logger_project%TYPE ,
+ p_ongoing_p in pm_projects.ongoing_p%TYPE ,
+ p_status_id in pm_projects.status_id%TYPE ,
+ p_customer_id in pm_projects.customer_id%TYPE ,
+ p_creation_date in date default sysdate,
+ p_creation_user in integer,
+ p_creation_ip in varchar2,
+ p_package_id in integer
+ ) return integer;
+
+ function new_unique_name (p_package_id in integer
+ ) return varchar;
+
+end pm_project;
+/
+
+show errors
+
+create or replace package body pm_project as
+ function name ( p_pm_project_id in pm_projects.project_id%TYPE
+ ) return varchar2
+ is
+ v_pm_project_name varchar2(500);
+ begin
+ select name || '_' || p_pm_project_id
+ into v_pm_project_name
+ from pm_projectsx
+ where item_id = p_pm_project_id;
+
+ return v_pm_project_name;
+ end name;
+
+ function new_root_folder (p_package_id in apm_packages.package_id%TYPE
+ ) return integer
+ is
+ v_folder_id cr_folders.folder_id%TYPE;
+ v_folder_name cr_items.name%TYPE;
+ begin
+ v_folder_name := new_unique_name (p_package_id);
+
+ v_folder_id := content_folder.new (
+ name => v_folder_name,
+ label => 'Projects',
+ description => 'Project Repository',
+ parent_id => null,
+ context_id => p_package_id,
+ folder_id => null,
+ creation_date => sysdate,
+ creation_user => null,
+ creation_ip => null
+ );
+
+ -- Register the standard content types
+ content_folder.register_content_type (
+ folder_id => v_folder_id,
+ content_type => 'pm_project',
+ include_subtypes => 'f'
+ );
+
+ -- there is no facility in the API for adding in the package_id,
+ -- so we have to do it ourselves
+
+ update cr_folders
+ set package_id = p_package_id
+ where folder_id = v_folder_id;
+
+ -- TODO: Handle Permissions here for this folder.
+
+ return v_folder_id;
+ end new_root_folder;
+
+ function get_root_folder (p_package_id in apm_packages.package_id%TYPE ,
+ p_create_if_not_present_p char
+ ) return integer
+ is
+ v_folder_id cr_folders.folder_id%TYPE;
+ v_count integer;
+ begin
+ select count(*) into v_count
+ from cr_folders
+ where package_id = p_package_id;
+
+ -- raise notice 'count is % for package_id %', v_count, p_package_id;
+
+ if v_count > 1 then
+ raise_application_error(-20001, 'More than one project repository for this application instance');
+ elsif v_count = 1 then
+ select folder_id into v_folder_id
+ from cr_folders
+ where package_id = p_package_id;
+ else
+ if p_create_if_not_present_p = 't' then
+ -- Must be a new instance. Create a new root folder.
+ -- raise notice 'creating a new root repository folder';
+ v_folder_id := new_root_folder(p_package_id);
+ else
+ -- raise notice 'setting to null';
+ v_folder_id := null;
+ end if;
+ end if;
+
+ return v_folder_id;
+ end get_root_folder;
+
+ function new_project_item (
+ p_project_name in varchar2 ,
+ p_project_code in pm_projects.project_code%TYPE,
+ p_parent_id in integer ,
+ p_goal in pm_projects.goal%TYPE,
+ p_description in varchar2 ,
+ p_mime_type in varchar2 ,
+ p_planned_start_date in pm_projects.planned_start_date%TYPE ,
+ p_planned_end_date in pm_projects.planned_end_date%TYPE ,
+ p_actual_start_date in pm_projects.actual_start_date%TYPE ,
+ p_actual_end_date in pm_projects.actual_end_date%TYPE,
+ p_logger_project in pm_projects.logger_project%TYPE ,
+ p_ongoing_p in pm_projects.ongoing_p%TYPE ,
+ p_status_id in pm_projects.status_id%TYPE ,
+ p_customer_id in pm_projects.customer_id%TYPE ,
+ p_creation_date in date default sysdate,
+ p_creation_user in integer,
+ p_creation_ip in varchar2,
+ p_package_id in integer
+ ) return integer
+ is
+ v_item_id cr_items.item_id%TYPE;
+ v_revision_id cr_revisions.revision_id%TYPE;
+ v_id cr_items.item_id%TYPE;
+ v_parent_id cr_items.parent_id%TYPE;
+ begin
+
+ select acs_object_id_seq.nextval into v_id from dual;
+
+ v_parent_id := get_root_folder (p_package_id, 't');
+
+ -- raise notice 'v_parent_id (%) p_parent_id (%)', v_parent_id, p_parent_id;
+
+ if p_parent_id is not null
+ then
+ v_parent_id := p_parent_id;
+ end if;
+
+ -- raise notice 'v_parent_id (%) p_parent_id (%)', v_parent_id, p_parent_id;
+
+ v_item_id := content_item.new (
+ name => v_id,
+ parent_id => v_parent_id,
+ item_id => v_id ,
+ locale => null,
+ creation_date => p_creation_date,
+ creation_user => p_creation_user,
+ context_id => p_parent_id,
+ creation_ip => p_creation_ip,
+ item_subtype => 'content_item',
+ content_type => 'pm_project',
+ title => p_project_name,
+ description => p_description,
+ mime_type => p_mime_type,
+ nls_language => null,
+ data => null
+ );
+
+ v_revision_id := content_revision.new (
+ title => p_project_name,
+ description => p_description,
+ publish_date => sysdate,
+ mime_type => p_mime_type,
+ nls_language => NULL,
+ data => NULL,
+ item_id => v_item_id,
+ revision_id => NULL,
+ creation_date => p_creation_date,
+ creation_user => p_creation_user,
+ creation_ip => p_creation_ip
+ );
+
+ content_item.set_live_revision (v_revision_id);
+
+ insert into pm_projects (
+ project_id, project_code,
+ goal, planned_start_date,
+ planned_end_date, actual_start_date, actual_end_date,
+ logger_project, ongoing_p, estimated_finish_date,
+ earliest_finish_date, latest_finish_date,
+ actual_hours_completed,
+ estimated_hours_total, status_id, customer_id)
+ values (
+ v_revision_id, p_project_code,
+ p_goal, p_planned_start_date,
+ p_planned_end_date, p_actual_start_date,
+ p_actual_end_date, p_logger_project, p_ongoing_p,
+ p_planned_end_date,
+ p_planned_end_date, p_planned_end_date, '0',
+ '0', p_status_id, p_customer_id
+ );
+
+ acs_permission.grant_permission(
+ v_revision_id,
+ p_creation_user,
+ 'admin'
+ );
+
+ return v_revision_id;
+ end new_project_item;
+
+ procedure delete_project_item ( p_project_id in pm_projects.project_id%TYPE)
+ is
+ v_child_item_id cr_items.item_id%TYPE;
+ begin
+ -- raise NOTICE 'Deleting pm_project...';
+
+ for v_child in (select item_id
+ from cr_items
+ where parent_id = p_project_id and
+ content_type = 'pm_project')
+ loop
+ delete_project_item(v_child_item_id);
+ end loop;
+
+ delete from pm_projects where project_id in (select revision_id from pm_projectsx where item_id = p_project_id);
+
+ content_item.del(p_project_id);
+ end delete_project_item;
+
+
+ function new_project_revision (
+ p_item_id in integer ,
+ p_project_name in varchar2 ,
+ p_project_code in pm_projects.project_code%TYPE,
+ p_parent_id in integer ,
+ p_goal in pm_projects.goal%TYPE,
+ p_description in varchar2 ,
+ p_planned_start_date in pm_projects.planned_start_date%TYPE ,
+ p_planned_end_date in pm_projects.planned_end_date%TYPE ,
+ p_actual_start_date in pm_projects.actual_start_date%TYPE ,
+ p_actual_end_date in pm_projects.actual_end_date%TYPE,
+ p_logger_project in pm_projects.logger_project%TYPE ,
+ p_ongoing_p in pm_projects.ongoing_p%TYPE ,
+ p_status_id in pm_projects.status_id%TYPE ,
+ p_customer_id in pm_projects.customer_id%TYPE ,
+ p_creation_date in date default sysdate,
+ p_creation_user in integer,
+ p_creation_ip in varchar2,
+ p_package_id in integer
+ ) return integer
+ is
+ v_revision_id cr_revisions.revision_id%TYPE;
+ begin
+
+ -- the item_id is the project_id
+ v_revision_id := content_revision.new (
+ title => p_project_name,
+ description => p_description,
+ publish_date => sysdate,
+ mime_type => 'text/plain',
+ nls_language => NULL,
+ data => NULL,
+ item_id => p_item_id,
+ revision_id => NULL,
+ creation_date => p_creation_date,
+ creation_user => p_creation_user,
+ creation_ip => p_creation_ip
+ );
+
+ content_item.set_live_revision (v_revision_id);
+
+ insert into pm_projects (
+ project_id, project_code,
+ goal, planned_start_date,
+ planned_end_date, actual_start_date, actual_end_date,
+ logger_project,
+ ongoing_p, status_id, customer_id)
+ values (
+ v_revision_id, p_project_code,
+ p_goal, p_planned_start_date,
+ p_planned_end_date, p_actual_start_date,
+ p_actual_end_date,
+ p_logger_project, p_ongoing_p, p_status_id, p_customer_id);
+
+ acs_permission.grant_permission(
+ v_revision_id,
+ p_creation_user,
+ 'admin'
+ );
+
+ return v_revision_id;
+
+ end new_project_revision;
+
+ function new_unique_name (p_package_id in integer
+ ) return varchar
+ is
+ v_name cr_items.name%TYPE;
+ v_package_key apm_packages.package_key%TYPE;
+ v_id integer;
+ begin
+ select package_key into v_package_key from apm_packages
+ where package_id = p_package_id;
+
+ select acs_object_id_seq.nextval into v_id from dual;
+
+ -- Set the name
+ select v_package_key || '_' ||
+ to_char(sysdate, 'YYYYMMDD') || '_' ||
+ v_id into v_name
+ from dual;
+
+ return v_name;
+
+ end new_unique_name;
+end pm_project;
+/
+show errors
+
+----------------------------------
+-- Tasks
+----------------------------------
+
+-- When we created the acs object type above, we specified a
+-- 'name_method'. This is the name of a function that will return the
+-- name of the object. This is a convention ensuring that all objects
+-- can be identified. Now we have to build that function. In this case,
+-- we'll return a field called title as the name.
+create or replace package pm_task
+as
+ function name (p_pm_task_id in integer
+ ) return varchar2;
+
+ function new_task_item (
+ p_project_id in integer ,
+ p_title in varchar2,
+ p_description in varchar2,
+ p_mime_type in varchar2,
+ p_end_date in date,
+ p_percent_complete in numeric,
+ p_estimated_hours_work in numeric,
+ p_estimated_hours_work_min in numeric,
+ p_estimated_hours_work_max in numeric,
+ p_status_id in integer,
+ p_creation_date in date default sysdate,
+ p_creation_user in integer,
+ p_creation_ip in varchar2,
+ p_package_id in integer
+ ) return integer;
+
+ function new_task_revision (
+ p_task_id in integer,
+ p_project_id in integer ,
+ p_title in varchar2,
+ p_description in varchar2,
+ p_mime_type in varchar2,
+ p_end_date in date,
+ p_percent_complete in numeric,
+ p_estimated_hours_work in numeric,
+ p_estimated_hours_work_min in numeric,
+ p_estimated_hours_work_max in numeric,
+ p_actual_hours_worked in numeric,
+ p_status_id in integer,
+ p_creation_date in date default sysdate,
+ p_creation_user in integer,
+ p_creation_ip in varchar2,
+ p_package_id in integer
+ ) return integer;
+
+ procedure delete_task_item (p_task_id in integer);
+
+end pm_task;
+/
+show errors
+
+
+create or replace package body pm_task
+as
+ function name (p_pm_task_id in integer
+ ) return varchar2
+ is
+ v_pm_task_name cr_items.name%TYPE;
+ begin
+ select i.name || '_' || p_pm_task_id into v_pm_task_name
+ from cr_items i
+ where i.item_id = p_pm_task_id;
+
+ return v_pm_task_name;
+ end name;
+
+ function new_task_item (
+ p_project_id in integer ,
+ p_title in varchar2,
+ p_description in varchar2,
+ p_mime_type in varchar2,
+ p_end_date in date,
+ p_percent_complete in numeric,
+ p_estimated_hours_work in numeric,
+ p_estimated_hours_work_min in numeric,
+ p_estimated_hours_work_max in numeric,
+ p_status_id in integer,
+ p_creation_date in date default sysdate,
+ p_creation_user in integer,
+ p_creation_ip in varchar2,
+ p_package_id in integer
+ ) return integer
+ is
+ v_item_id cr_items.item_id%TYPE;
+ v_revision_id cr_revisions.revision_id%TYPE;
+ v_id cr_items.item_id%TYPE;
+ v_task_number integer;
+ begin
+ select acs_object_id_seq.nextval into v_id from dual;
+
+ -- We want to put the task under the project item
+ -- create the task_number
+
+ v_item_id := content_item.new (
+ name => v_id,
+ parent_id => p_project_id,
+ item_id => v_id,
+ locale => null,
+ creation_date => sysdate,
+ creation_user => p_creation_user,
+ context_id => p_package_id,
+ creation_ip => p_creation_ip,
+ item_subtype => 'content_item',
+ content_type => 'pm_task',
+ title => p_title,
+ description => p_description,
+ mime_type => p_mime_type,
+ nls_language => null,
+ data => null
+ );
+
+ v_revision_id := content_revision.new (
+ title => p_title,
+ description => p_description,
+ publish_date => sysdate,
+ mime_type => p_mime_type,
+ nls_language => NULL,
+ data => NULL,
+ item_id => v_item_id,
+ revision_id => NULL,
+ creation_date => sysdate,
+ creation_user => p_creation_user,
+ creation_ip => p_creation_ip
+ );
+
+ content_item.set_live_revision (v_revision_id);
+
+ insert into pm_tasks (
+ task_id, task_number, status)
+ values (
+ v_item_id, v_task_number, p_status_id);
+
+ insert into pm_tasks_revisions (
+ task_revision_id, end_date, percent_complete, estimated_hours_work, estimated_hours_work_min, estimated_hours_work_max, actual_hours_worked)
+ values (
+ v_revision_id, p_end_date, p_percent_complete, p_estimated_hours_work, p_estimated_hours_work_min, p_estimated_hours_work_max, '0');
+
+ acs_permission.grant_permission(
+ v_revision_id,
+ p_creation_user,
+ 'admin'
+ );
+
+ return v_revision_id;
+
+ end new_task_item;
+
+ function new_task_revision (
+ p_task_id in integer,
+ p_project_id in integer ,
+ p_title in varchar2,
+ p_description in varchar2,
+ p_mime_type in varchar2,
+ p_end_date in date,
+ p_percent_complete in numeric,
+ p_estimated_hours_work in numeric,
+ p_estimated_hours_work_min in numeric,
+ p_estimated_hours_work_max in numeric,
+ p_actual_hours_worked in numeric,
+ p_status_id in integer,
+ p_creation_date in date default sysdate,
+ p_creation_user in integer,
+ p_creation_ip in varchar2,
+ p_package_id in integer
+ ) return integer
+ is
+ v_revision_id cr_revisions.revision_id%TYPE;
+ v_id cr_items.item_id%TYPE;
+ begin
+ select acs_object_id_seq.nextval into v_id from dual;
+
+ -- We want to put the task under the project item
+ update cr_items
+ set parent_id = p_project_id
+ where item_id = p_task_id;
+
+ v_revision_id := content_revision.new (
+ title => p_title,
+ description => p_description,
+ publish_date => sysdate,
+ mime_type => p_mime_type,
+ nls_language => NULL,
+ data => NULL,
+ item_id => p_task_id,
+ revision_id => NULL,
+ creation_date => sysdate,
+ creation_user => p_creation_user,
+ creation_ip => p_creation_ip
+ );
+
+ content_item.set_live_revision (v_revision_id);
+
+ insert into pm_tasks_revisions (
+ task_revision_id, end_date, percent_complete, estimated_hours_work, estimated_hours_work_min, estimated_hours_work_max, actual_hours_worked)
+ values (
+ v_revision_id, p_end_date, p_percent_complete, p_estimated_hours_work, p_estimated_hours_work_min, p_estimated_hours_work_max, p_actual_hours_worked);
+
+ update pm_tasks
+ set status = p_status_id
+ where task_id = p_task_id;
+
+ acs_permission.grant_permission(
+ v_revision_id,
+ p_creation_user,
+ 'admin'
+ );
+
+ return v_revision_id;
+ end new_task_revision;
+
+ procedure delete_task_item (p_task_id in integer)
+ is
+ begin
+ delete from pm_tasks_revisions
+ where task_revision_id in (select revision_id from pm_tasks_revisionsx where item_id = p_task_id);
+
+ delete from pm_tasks
+ where task_id = p_task_id;
+
+ content_item.del(p_task_id);
+ end delete_task_item ;
+end pm_task;
+/
+
+show errors
+
+
+
+
Index: openacs-4/packages/project-manager/sql/oracle/project-manager-notifications-create.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/sql/oracle/project-manager-notifications-create.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/sql/oracle/project-manager-notifications-create.sql 29 Apr 2005 17:43:36 -0000 1.1
@@ -0,0 +1,66 @@
+-- Following directions at
+-- http://openacs.org/doc/openacs-HEAD/tutorial-notifications.html
+
+-- using pm_task_notif_type instead of lars_blogger_notif_type
+-- using project-manager instead of lars-blogger
+
+declare
+ impl_id integer;
+ v_foo integer;
+begin
+
+ -- the notification type impl
+ impl_id := acs_sc_impl.new (
+ impl_contract_name => 'NotificationType',
+ impl_name => 'pm_task_notif_type',
+ impl_owner_name => 'project-manager'
+ );
+
+ v_foo := acs_sc_impl_alias.new (
+ impl_contract_name => 'NotificationType',
+ impl_name => 'pm_task_notif_type',
+ impl_operation_name => 'GetURL',
+ impl_alias => 'pm::task::get_url',
+ impl_pl => 'TCL'
+ );
+
+ v_foo := acs_sc_impl_alias.new (
+ impl_contract_name => 'NotificationType',
+ impl_name => 'pm_task_notif_type',
+ impl_operation_name => 'ProcessReply',
+ impl_alias => 'pm::task::process_reply',
+ impl_pl => 'TCL'
+ );
+
+ acs_sc_binding.new (
+ contract_name => 'NotificationType',
+ impl_name => 'pm_task_notif_type'
+ );
+
+ v_foo:= notification_type.new (
+ type_id => NULL,
+ sc_impl_id => impl_id,
+ short_name => 'pm_task_notif',
+ pretty_name => 'Task Notification',
+ description => 'Notifications of task changes',
+ creation_date => sysdate ,
+ creation_user => null,
+ creation_ip => null,
+ context_id => NULL
+ );
+
+ -- enable the various intervals and delivery methods
+ insert into notification_types_intervals
+ (type_id, interval_id)
+ select v_foo, interval_id
+ from notification_intervals where name in ('instant','hourly','daily');
+
+ insert into notification_types_del_methods
+ (type_id, delivery_method_id)
+ select v_foo, delivery_method_id
+ from notification_delivery_methods where short_name in ('email');
+
+end;
+/
+
+show errors
Index: openacs-4/packages/project-manager/sql/oracle/project-manager-notifications-drop.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/sql/oracle/project-manager-notifications-drop.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/sql/oracle/project-manager-notifications-drop.sql 29 Apr 2005 17:43:36 -0000 1.1
@@ -0,0 +1,92 @@
+--
+-- Project Manager
+--
+-- @author jader@bread.com
+-- @author gwong@orchardlabs.com,ben@openforce.biz
+-- @creation-date 2002-05-16
+--
+-- This code is newly concocted by Ben, but with significant concepts and code
+-- lifted from Gilbert's UBB forums. Thanks Orchard Labs.
+-- Jade in turn lifted this from gwong and ben.
+--
+
+create function inline_0 ()
+returns integer as '
+declare
+ row record;
+begin
+ for row in select nt.type_id
+ from notification_types nt
+ where nt.short_name in (''pm_task_notif'')
+ loop
+ perform notification_type__delete(row.type_id);
+ end loop;
+
+ return null;
+end;' language 'plpgsql';
+
+select inline_0();
+drop function inline_0 ();
+
+--
+-- Service contract drop stuff was missing - Roberto Mello
+--
+
+create function inline_0() returns integer as '
+declare
+ impl_id integer;
+ v_foo integer;
+begin
+
+ -- the notification type impl
+ impl_id := acs_sc_impl__get_id (
+ ''NotificationType'', -- impl_contract_name
+ ''pm_task_notif_type'' -- impl_name
+ );
+
+ PERFORM acs_sc_binding__delete (
+ ''NotificationType'',
+ ''pm_task_notif_type''
+ );
+
+ v_foo := acs_sc_impl_alias__delete (
+ ''NotificationType'', -- impl_contract_name
+ ''pm_task_notif_type'', -- impl_name
+ ''GetURL'' -- impl_operation_name
+ );
+
+ v_foo := acs_sc_impl_alias__delete (
+ ''NotificationType'', -- impl_contract_name
+ ''pm_task_notif_type'', -- impl_name
+ ''ProcessReply'' -- impl_operation_name
+ );
+
+ select into v_foo type_id
+ from notification_types
+ where sc_impl_id = impl_id
+ and short_name = ''pm_task_notif'';
+
+ perform notification_type__delete (v_foo);
+
+ delete from notification_types_intervals
+ where type_id = v_foo
+ and interval_id in (
+ select interval_id
+ from notification_intervals
+ where name in (''instant'',''hourly'',''daily'')
+ );
+
+ delete from notification_types_del_methods
+ where type_id = v_foo
+ and delivery_method_id in (
+ select delivery_method_id
+ from notification_delivery_methods
+ where short_name in (''email'')
+ );
+
+ return (0);
+end;
+' language 'plpgsql';
+
+select inline_0();
+drop function inline_0();
Index: openacs-4/packages/project-manager/sql/oracle/project-manager-table-create.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/sql/oracle/project-manager-table-create.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/sql/oracle/project-manager-table-create.sql 29 Apr 2005 17:43:36 -0000 1.1
@@ -0,0 +1,638 @@
+-- packages/project-manager/sql/postgresql/project-manager-table-create.sql
+--
+-- @author jader@bread.com
+-- @author ncarroll@ee.usyd.edu.au was involved in creating the initial CR version
+-- @author everyone else involved in this thread: http://openacs.org/forums/message-view?message_id=90742
+-- @creation-date 2003-05-15
+--
+
+-- PROJECTS
+
+create sequence pm_project_status_seq start with 3;
+
+create table pm_project_status (
+ status_id integer
+ constraint pm_project_status_pk
+ primary key,
+ description varchar(100),
+ -- closed or open
+ status_type char(1) default 'c'
+ constraint pm_projects_status_type_ck
+ check (status_type in ('c','o'))
+);
+
+insert into pm_project_status (status_id, description, status_type) values
+(1, 'Open', 'o');
+insert into pm_project_status (status_id, description, status_type) values
+(2, 'Closed', 'c');
+
+
+-- project revisions, items are kept in cr_items
+
+create table pm_projects (
+ project_id integer
+ constraint pm_proj_rev_fk
+ references cr_revisions on delete cascade
+ constraint pm_proj_rev_pk
+ primary key,
+ -- a user-specified project code
+ project_code varchar(255),
+ goal varchar(4000),
+ planned_start_date date,
+ planned_end_date date,
+ actual_start_date date,
+ actual_end_date date,
+ status_id integer
+ constraint pm_projects_status_id_nn
+ not null
+ constraint pm_projects_status_id_fk
+ references pm_project_status,
+ -- if ongoing_p is true, then actual_end_date must be null
+ ongoing_p char(1) default 'f'
+ constraint pm_projects_ongoing_p_ck
+ check (ongoing_p in ('t','f')),
+ estimated_finish_date date,
+ earliest_finish_date date,
+ latest_finish_date date,
+ -- denormalized, taken from logger
+ actual_hours_completed numeric,
+ estimated_hours_total numeric,
+ -- The logger package keeps its own projects table
+ logger_project integer
+ constraint pm_projects_logger_pj_nn
+ not null
+ constraint pm_projects_logger_pj_fk
+ references logger_projects
+);
+
+-- create type
+begin
+ content_type.create_type (
+ content_type => 'pm_project',
+ supertype => 'content_revision',
+ pretty_name => 'Project',
+ pretty_plural => 'Projects',
+ table_name => 'pm_projects',
+ id_column => 'project_id',
+ name_method => 'pm_project.name'
+ );
+end;
+/
+show errors
+
+-- other fields are added in too. See the -custom script.
+
+
+-- ROLES
+
+create sequence pm_role_seq start with 4;
+
+create table pm_roles (
+ role_id integer
+ constraint pm_role_id_pk
+ primary key,
+ one_line varchar(100)
+ constraint pm_role_one_line_uq
+ unique,
+ description varchar(2000),
+ sort_order integer,
+ is_observer_p char(1) default 'f'
+ constraint pm_role_is_observer_ck
+ check (is_observer_p in ('t','f'))
+);
+
+
+comment on table pm_roles is '
+ Roles represent the way in which a party participates in a project
+ or task. For example, they could be a manager, or client, or
+ participant.. The sort order determines what order it is displayed
+ in. The is_observer_p specifies whether they are directly
+ responsible for the task, or are just observers on it.
+';
+
+insert into pm_roles (role_id, one_line, description, sort_order) values ('1','Lead','Team members who are responsible for the completion of the project','10');
+insert into pm_roles (role_id, one_line, description, sort_order) values ('2','Player','A person on the team responsible for completion of the project','20');
+insert into pm_roles (role_id, one_line, description, sort_order, is_observer_p) values ('3','Watcher','A person interested in developments, possibly helping out on it.','30','t');
+
+
+create table pm_default_roles (
+ role_id integer
+ constraint pm_default_role_fk
+ references pm_roles
+ on delete cascade,
+ party_id integer
+ constraint pm_default_role_party_fk
+ references parties(party_id)
+ on delete cascade,
+ constraint pm_default_roles_uq
+ unique (role_id, party_id)
+);
+
+comment on table pm_default_roles is '
+ Specifies what role a person is a part of by default
+';
+
+-- PROJECT ASSIGNMENT
+
+create table pm_project_assignment (
+ project_id integer
+ constraint pm_proj_role_map_project_fk
+ references cr_items
+ on delete cascade,
+ role_id integer
+ constraint pm_project_role_map_role_fk
+ references pm_roles,
+ party_id integer
+ constraint pm_project_role_map_user_id_fk
+ references parties(party_id)
+ on delete cascade,
+ constraint pm_project_assignment_uq
+ unique (project_id, role_id, party_id)
+);
+
+
+comment on table pm_project_assignment is '
+ Maps who is a part of what project, and in what capacity
+';
+
+
+-- TASKS
+
+-- we create two tables to store task information
+-- the information that we keep revisions on is in the
+-- pm_task_revisions table, the rest is in pm_task
+
+create sequence pm_task_status_seq start with 3;
+
+create table pm_task_status (
+ status_id integer
+ constraint pm_task_status_pk
+ primary key,
+ description varchar(100),
+ -- closed or open
+ status_type char(1) default 'c'
+ constraint pm_task_status_type_ck
+ check (status_type in ('c','o'))
+);
+
+insert into pm_task_status (status_id, description, status_type) values
+(1, 'Open', 'o');
+insert into pm_task_status (status_id, description, status_type) values
+(2, 'Closed', 'c');
+
+
+create sequence pm_tasks_number_seq;
+
+create table pm_tasks (
+ task_id integer
+ constraint pm_tasks_task_id_fk
+ references cr_items
+ on delete cascade
+ constraint pm_task_task_id_pk
+ primary key,
+ task_number integer,
+ status integer
+ constraint pm_tasks_task_status_fk
+ references pm_task_status,
+ deleted_p char(1) default 'f'
+ constraint pm_tasks_deleted_p_ck
+ check (deleted_p in ('t','f'))
+);
+
+CREATE OR REPLACE view
+pm_tasks_active as
+ SELECT task_id, task_number, status FROM pm_tasks where deleted_p = 'f';
+
+
+create table pm_tasks_revisions (
+ task_revision_id integer
+ constraint pm_task_revs_id_fk
+ references cr_revisions
+ on delete cascade
+ constraint pm_task_revs_id_pk
+ primary key,
+ -- dates are optional, because it may be computed in reference
+ -- to all other items, or simply not have a deadline
+ end_date date,
+ -- keep track of completion status
+ percent_complete numeric
+ constraint pm_task_per_complete_gt_ck
+ check(percent_complete >= 0)
+ constraint pm_task_per_complete_lt_ck
+ check(percent_complete <= 100),
+ estimated_hours_work numeric,
+ -- PERT charts require minimum and maximum estimates
+ -- these are optionally used
+ estimated_hours_work_min numeric,
+ estimated_hours_work_max numeric,
+ -- this should be computed by checking with logger? The actual
+ -- data should be in logger, logged by who did it, when etc..
+ -- or we can create a separate table to keep track of task hours
+ -- and make sure its data model is similar to logger?
+ actual_hours_worked numeric,
+ -- network diagram stuff, computed
+ earliest_start date,
+ earliest_finish date,
+ latest_start date,
+ latest_finish date
+);
+
+-- create the content type
+begin
+ content_type.create_type (
+ content_type => 'pm_task',
+ supertype => 'content_revision',
+ pretty_name => 'Task',
+ pretty_plural => 'Tasks',
+ table_name => 'pm_tasks_revisions',
+ id_column => 'task_revision_id',
+ name_method => 'pm_task__name'
+ );
+end;
+/
+show errors
+
+-- add in attributes
+
+declare
+ attribute_id integer;
+begin
+ attribute_id := content_type.create_attribute (
+ content_type => 'pm_task',
+ attribute_name => 'end_date',
+ datatype => 'date',
+ pretty_name => 'End date',
+ pretty_plural => 'End dates',
+ sort_order => null,
+ default_value => null,
+ column_spec => 'date'
+ );
+
+ attribute_id := content_type.create_attribute (
+ content_type => 'pm_task',
+ attribute_name => 'percent_complete',
+ datatype => 'number',
+ pretty_name => 'Percent complete',
+ pretty_plural => 'Percents complete',
+ sort_order => null,
+ default_value => null,
+ column_spec => 'numeric'
+ );
+
+ attribute_id := content_type.create_attribute (
+ content_type => 'pm_task',
+ attribute_name => 'estimated_hours_work',
+ datatype => 'number',
+ pretty_name => 'Estimated hours work',
+ pretty_plural => 'Estimated hours work',
+ sort_order => null,
+ default_value => null,
+ column_spec => 'numeric'
+ );
+
+ attribute_id := content_type.create_attribute (
+ content_type => 'pm_task',
+ attribute_name => 'estimated_hours_work_min',
+ datatype => 'number',
+ pretty_name => 'Estimated minimum hours',
+ pretty_plural => 'Estimated minimum hours',
+ sort_order => null,
+ default_value => null,
+ column_spec => 'numeric'
+ );
+
+ attribute_id := content_type.create_attribute (
+ content_type => 'pm_task',
+ attribute_name => 'estimated_hours_work_max',
+ datatype => 'number',
+ pretty_name => 'Estimated maximum hours',
+ pretty_plural => 'Estimated maximum hours',
+ sort_order => null,
+ default_value => null,
+ column_spec => 'numeric'
+ );
+
+ attribute_id := content_type.create_attribute (
+ content_type => 'pm_task',
+ attribute_name => 'actual_hours_worked',
+ datatype => 'number',
+ pretty_name => 'Actual hours worked',
+ pretty_plural => 'Actual hours worked',
+ sort_order => null,
+ default_value => null,
+ column_spec => 'numeric'
+ );
+
+ attribute_id := content_type.create_attribute (
+ content_type => 'pm_task',
+ attribute_name => 'earliest_start',
+ datatype => 'date',
+ pretty_name => 'Earliest start date',
+ pretty_plural => 'Earliest start dates',
+ sort_order => null,
+ default_value => null,
+ column_spec => 'date'
+ );
+
+ attribute_id := content_type.create_attribute (
+ content_type => 'pm_task',
+ attribute_name => 'earliest_finish',
+ datatype => 'date',
+ pretty_name => 'Earliest finish date',
+ pretty_plural => 'Earliest finish dates',
+ sort_order => null,
+ default_value => null,
+ column_spec => 'date'
+ );
+
+ attribute_id := content_type.create_attribute (
+ content_type => 'pm_task',
+ attribute_name => 'latest_start',
+ datatype => 'date',
+ pretty_name => 'Latest start date',
+ pretty_plural => 'Latest start dates',
+ sort_order => null,
+ default_value => null,
+ column_spec => 'date'
+ );
+
+ attribute_id := content_type.create_attribute (
+ content_type => 'pm_task',
+ attribute_name => 'latest_finish',
+ datatype => 'date',
+ pretty_name => 'Latest finish date',
+ pretty_plural => 'Latest finish dates',
+ sort_order => null,
+ default_value => null,
+ column_spec => 'date'
+ );
+end;
+/
+
+show errors
+
+create table pm_task_logger_proj_map (
+ task_item_id integer
+ constraint pm_task_log_proj_map_t_nn
+ not null
+ constraint pm_task_log_proj_map_t_fk
+ references pm_tasks
+ on delete cascade,
+ logger_entry integer
+ constraint pm_task_log_proj_map_l_nn
+ not null
+ constraint pm_task_log_proj_map_l_fk
+ references logger_entries
+ on delete cascade,
+ constraint pm_task_logger_proj_map_uq
+ unique (task_item_id, logger_entry)
+);
+
+
+-- DEPENDENCIES
+
+-- dependency types
+-- such as:
+-- cannot start until Task X finishes
+-- cannot start until Task X begins
+-- cannot finish until Task X finishes
+-- cannot finish until Task X begins
+
+create table pm_task_dependency_types (
+ short_name varchar(100)
+ constraint pm_task_const_sn_pk
+ primary key,
+ description varchar(1000)
+);
+
+insert into pm_task_dependency_types (short_name, description) values ('start_before_start','Starts before this starts');
+insert into pm_task_dependency_types (short_name, description) values ('start_before_finish','Starts before this finishes');
+insert into pm_task_dependency_types (short_name, description) values ('finish_before_start','Finishes before this starts');
+insert into pm_task_dependency_types (short_name, description) values ('finish_before_finish','Finishes before this finishes');
+
+
+create sequence pm_task_dependency_seq;
+
+create table pm_task_dependency (
+ dependency_id integer
+ constraint pm_task_const_id_pk
+ primary key,
+ task_id integer
+ constraint pm_task_const_task_id_nn
+ not null
+ constraint pm_task_const_task_id_fk
+ references pm_tasks
+ on delete cascade,
+ parent_task_id integer
+ constraint pm_tasks_const_parent_id_nn
+ not null
+ constraint pm_tasks_const_parent_id_fk
+ references pm_tasks
+ on delete cascade,
+ dependency_type varchar(100)
+ constraint pm_tasks_const_type_nn
+ not null
+ constraint pm_tasks_const_type_fk
+ references pm_task_dependency_types,
+ constraint pm_task_dependency_uq unique (task_id, parent_task_id)
+);
+
+
+-- WORKGROUPS
+
+create sequence pm_workgroup_seq;
+
+create table pm_workgroup (
+ workgroup_id integer
+ constraint pm_workgroup_id_pk
+ primary key,
+ one_line varchar(100)
+ constraint pm_workgroup_one_line_uq
+ unique,
+ description varchar(2000),
+ sort_order integer
+);
+
+create table pm_workgroup_parties (
+ workgroup_id integer
+ constraint pm_workgroup_parties_wg_id_fk
+ references pm_workgroup(workgroup_id)
+ on delete cascade,
+ party_id integer
+ constraint pm_workgroup_party_fk
+ references parties(party_id)
+ on delete cascade,
+ role_id integer
+ constraint pm_workgroup_role_id
+ references pm_roles,
+ constraint pm_workgroup_parties_uq
+ unique (workgroup_id, party_id, role_id)
+);
+
+
+-- TASK ASSIGNMENTS
+
+create table pm_task_assignment (
+ task_id integer
+ constraint pm_task_assignment_task_fk
+ references pm_tasks(task_id)
+ on delete cascade,
+ role_id integer
+ constraint pm_task_assignment_role_fk
+ references pm_roles,
+ party_id integer
+ constraint pm_task_assignment_party_fk
+ references parties(party_id)
+ on delete cascade,
+ constraint pm_task_assignment_uq
+ unique (task_id, role_id, party_id)
+);
+
+
+comment on table pm_task_assignment is '
+ Maps who is a part of what task, and in what capacity
+';
+
+create table pm_task_xref (
+ task_id_1 integer
+ constraint pm_task_xref_task1_nn
+ not null
+ constraint pm_task_xref_task1_fk
+ references pm_tasks(task_id)
+ on delete cascade,
+ task_id_2 integer
+ constraint pm_task_xref_task2_nn
+ not null
+ constraint pm_task_xref_task2_fk
+ references pm_tasks(task_id)
+ on delete cascade,
+ constraint pm_task_xref_lt check (task_id_1 < task_id_2)
+);
+
+comment on table pm_task_xref is '
+ Maps related tasks.
+';
+
+
+-- PROCESSES
+
+create sequence pm_process_seq;
+
+create table pm_process (
+ process_id integer
+ constraint pm_process_id_pk
+ primary key,
+ one_line varchar(200)
+ constraint pm_process_one_line_nn
+ not null,
+ description varchar(1000),
+ party_id integer
+ constraint pm_process_party_fk
+ references parties
+ constraint pm_process_party_nn
+ not null,
+ creation_date date
+);
+
+comment on table pm_process is '
+ Processes are a set of templates for tasks, so that people can
+ create sets of tasks quickly. Their structure needs to match that of
+ tasks. The process holds the meta information, and is also an identifier
+ that is used by the user to select which process they''d like to copy or
+ use
+';
+
+create sequence pm_process_task_seq;
+
+create table pm_process_task (
+ process_task_id integer
+ constraint pm_process_task_id_pk
+ primary key,
+ process_id integer
+ constraint pm_process_process_id_fk
+ references
+ pm_process
+ constraint pm_process_process_id_nn
+ not null,
+ one_line varchar(200)
+ constraint pm_process_task_one_line_nn
+ not null,
+ description varchar(4000),
+ -- dates are optional, because it may be computed in reference
+ -- to all other items, or simply not have a deadline
+ -- percent complete is always 0
+ estimated_hours_work numeric,
+ -- PERT charts require minimum and maximum estimates
+ -- these are optionally used
+ estimated_hours_work_min numeric,
+ estimated_hours_work_max numeric,
+ ordering integer
+);
+
+comment on table pm_process_task is '
+ A template for the tasks that will be created by the process
+';
+
+create sequence pm_process_task_dependency_seq;
+
+create table pm_process_task_dependency (
+ dependency_id integer
+ constraint pm_proc_task_dependcy_pk
+ primary key,
+ process_task_id integer
+ constraint pm_proc_task_proc_task_fk
+ references pm_process_task
+ on delete cascade,
+ parent_task_id integer
+ constraint pm_proc_task_parent_id_fk
+ references pm_process_task
+ on delete cascade,
+ dependency_type varchar(100)
+ constraint pm_process_task_dep_type
+ references pm_task_dependency_types,
+ constraint pm_proc_task_depend_uq
+ unique (process_task_id, parent_task_id)
+);
+
+comment on table pm_process_task_dependency is '
+ Keeps track of dependencies. Used to create the dependencies in the
+ new tasks.
+';
+
+create table pm_process_task_assignment (
+ process_task_id integer
+ constraint pm_proc_task_assign_task_fk
+ references pm_process_task(process_task_id)
+ on delete cascade,
+ role_id integer
+ constraint pm_proc_task_assign_role_fk
+ references pm_roles,
+ party_id integer
+ constraint pm_proc_task_assign_party_fk
+ references parties(party_id)
+ on delete cascade,
+ constraint pm_proc_task_assgn_uq
+ unique (process_task_id, role_id, party_id)
+);
+
+
+comment on table pm_process_task_assignment is '
+ Maps who is assigned to process tasks. These will be the default people
+ assigned to the new tasks
+';
+
+create table pm_users_viewed (
+ viewing_user integer constraint
+ pm_usrs_viewed_viewing_user_fk
+ references parties,
+ viewed_user integer constraint
+ pm_usrs_viewed_viewed_user_fk
+ references parties
+);
+
+comment on table pm_users_viewed is '
+ Used to keep track of what users to see on the task calendar and other
+ views.
+';
+
+@@project-manager-custom-create.sql
Index: openacs-4/packages/project-manager/sql/postgresql/project-manager-create.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/sql/postgresql/project-manager-create.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/sql/postgresql/project-manager-create.sql 29 Apr 2005 17:43:36 -0000 1.1
@@ -0,0 +1,12 @@
+--
+-- packages/project-manager/sql/postgresql/project-manager-create.sql
+--
+-- @author jade@bread.com
+-- @creation-date 2003-05-15
+-- @cvs-id $Id: project-manager-create.sql,v 1.1 2005/04/29 17:43:36 timoh Exp $
+--
+--
+
+\i project-manager-table-create.sql
+\i project-manager-functions-create.sql
+\i project-manager-notifications-create.sql
Index: openacs-4/packages/project-manager/sql/postgresql/project-manager-custom-create.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/sql/postgresql/project-manager-custom-create.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/sql/postgresql/project-manager-custom-create.sql 29 Apr 2005 17:43:36 -0000 1.1
@@ -0,0 +1,38 @@
+--
+-- packages/project-manager/sql/postgresql/project-manager-customize.sql
+--
+-- @author jader@bread.com
+-- @creation-date 2003-12-05
+--
+
+-- this file is used to add custom columns to the projects table.
+-- you can then customize the columns shown
+
+-- if you do set this up, you need to set the parameter in the admin
+-- UI, so that the add-edit page will know that there is custom code,
+-- You'll need to create an add-edit-custom page, filling in the skeleton there
+
+-- you should use the content_type__create_attribute procedure to add
+-- in columns so that the views are correctly recreated.
+
+-- PROJECTS
+
+-- example, using customer
+-- this is actually done in the table-create script
+
+-- this adds in the customer column. This is an example of how
+-- the custom columns are added in. I put this here as a reminder
+-- that other columns can be added in as well. These custom items
+-- are in the custom-create.sql script
+
+select content_type__create_attribute(
+ 'pm_project',
+ 'customer_id',
+ 'integer',
+ 'Customer',
+ 'Customers',
+ null,
+ null,
+ 'integer constraint pm_project_customer_fk references organizations'
+);
+
Index: openacs-4/packages/project-manager/sql/postgresql/project-manager-custom-drop.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/sql/postgresql/project-manager-custom-drop.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/sql/postgresql/project-manager-custom-drop.sql 29 Apr 2005 17:43:36 -0000 1.1
@@ -0,0 +1,12 @@
+-- packages/project-manager/sql/project-manager-drop.sql
+-- drop script
+--
+-- @author jade@bread.com
+-- @creation-date 2003-12-05
+-- @cvs-id $Id: project-manager-custom-drop.sql,v 1.1 2005/04/29 17:43:36 timoh Exp $
+--
+
+-- drop any custom tables here.
+
+select content_type__drop_attribute ('pm_project', 'customer_id', 't');
+
Index: openacs-4/packages/project-manager/sql/postgresql/project-manager-drop.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/sql/postgresql/project-manager-drop.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/sql/postgresql/project-manager-drop.sql 29 Apr 2005 17:43:36 -0000 1.1
@@ -0,0 +1,217 @@
+-- packages/project-manager/sql/project-manager-drop.sql
+-- drop script
+--
+-- @author jade@bread.com
+-- @creation-date 2003-05-15
+-- @cvs-id $Id: project-manager-drop.sql,v 1.1 2005/04/29 17:43:36 timoh Exp $
+--
+
+--------
+-- TASKS
+--------
+
+\i project-manager-custom-drop.sql
+\i project-manager-notifications-drop.sql
+
+drop table pm_task_logger_proj_map;
+
+create function inline_0 ()
+returns integer as '
+declare
+ v_item RECORD;
+
+begin
+ for v_item in select
+ item_id
+ from
+ cr_items
+ where
+ content_type = ''pm_task''
+ LOOP
+ PERFORM pm_task__delete_task_item(v_item.item_id);
+ end loop;
+
+ return 0;
+end;
+' language 'plpgsql';
+
+select inline_0();
+drop function inline_0();
+
+-- unregister content_types from folder
+create function inline_0 ()
+returns integer as '
+declare
+ v_folder_id cr_folders.folder_id%TYPE;
+ v_item_id cr_items.item_id%TYPE;
+ v_item_cursor RECORD;
+begin
+
+ -- delete all contents of projects folder
+ FOR v_item_cursor IN
+ select
+ item_id
+ from
+ cr_items
+ where
+ content_type = ''pm_task''
+ LOOP
+ PERFORM pm_project__delete_task_item(v_item_cursor.item_id);
+ END LOOP;
+
+ -- this table must not hold reference to ''pm_tasks'' type
+ delete from cr_folder_type_map where content_type = ''pm_tasks'';
+
+ return 0;
+end;
+' language 'plpgsql';
+
+select inline_0();
+drop function inline_0();
+
+-- unregister content_types from folder
+create function inline_0 ()
+returns integer as '
+declare
+ v_folder_id cr_folders.folder_id%TYPE;
+ v_item_id cr_items.item_id%TYPE;
+ v_item_cursor RECORD;
+begin
+
+ -- delete all contents of projects folder
+ FOR v_item_cursor IN
+ select
+ item_id
+ from
+ cr_items
+ where
+ content_type = ''pm_project''
+ LOOP
+ PERFORM pm_project__delete_project_item(v_item_cursor.item_id);
+ END LOOP;
+
+ return 0;
+end;
+' language 'plpgsql';
+
+select inline_0();
+drop function inline_0();
+
+-- unregister content_types from folder
+create function inline_0 ()
+returns integer as '
+declare
+ v_folder_id cr_folders.folder_id%TYPE;
+ v_item_id cr_items.item_id%TYPE;
+ v_item_cursor RECORD;
+begin
+
+ FOR v_item_cursor IN
+ select folder_id from cr_folders where description=''Project Repository''
+ LOOP
+ PERFORM content_folder__unregister_content_type (
+ v_item_cursor.folder_id, -- folder_id
+ ''pm_project'', -- content_type
+ ''t'' -- include_subtypes
+ );
+ PERFORM content_folder__delete(v_item_cursor.folder_id);
+ END LOOP;
+
+ -- this table must not hold reference to ''pm_project'' type
+ delete from cr_folder_type_map where content_type = ''pm_project'';
+
+ return 0;
+end;
+' language 'plpgsql';
+
+select inline_0();
+drop function inline_0();
+
+
+-- task dependency types
+drop table pm_task_dependency_types cascade;
+drop table pm_task_dependency cascade;
+drop sequence pm_task_dependency_seq;
+drop sequence pm_tasks_number_seq;
+
+select content_type__drop_attribute ('pm_task', 'end_date', 't');
+select content_type__drop_attribute ('pm_task', 'percent_complete', 't');
+select content_type__drop_attribute ('pm_task', 'estimated_hours_work', 't');
+select content_type__drop_attribute ('pm_task', 'estimated_hours_work_min', 't');
+select content_type__drop_attribute ('pm_task', 'estimated_hours_work_max', 't');
+select content_type__drop_attribute ('pm_task', 'actual_hours_worked', 't');
+select content_type__drop_attribute ('pm_task', 'earliest_start', 't');
+select content_type__drop_attribute ('pm_task', 'earliest_finish', 't');
+select content_type__drop_attribute ('pm_task', 'latest_start', 't');
+select content_type__drop_attribute ('pm_task', 'latest_finish', 't');
+
+-------------
+-- WORKGROUPS
+-------------
+
+drop sequence pm_workgroup_seq;
+drop table pm_workgroup_parties;
+drop table pm_workgroup;
+
+------------
+-- PROCESSES
+------------
+
+drop sequence pm_process_seq;
+drop sequence pm_process_task_seq;
+drop sequence pm_process_task_dependency_seq;
+
+drop table pm_process_task_assignment cascade;
+drop table pm_process_task_dependency cascade;
+drop table pm_process_task cascade;
+drop table pm_process cascade;
+
+---------
+-- OTHERS
+---------
+drop table pm_default_roles cascade;
+drop table pm_project_assignment cascade;
+drop table pm_task_assignment cascade;
+drop table pm_roles cascade;
+drop sequence pm_role_seq cascade;
+
+
+select drop_package('pm_task');
+
+
+-----------
+-- PROJECTS
+-----------
+
+--drop permissions
+delete from acs_permissions where object_id in (select project_id from pm_projects);
+
+
+-- drop package, which drops all functions created with define_function_args
+select drop_package('pm_project');
+
+--drop table
+drop table pm_projects cascade;
+
+drop sequence pm_project_status_seq;
+drop table pm_project_status cascade;
+
+
+
+drop sequence pm_task_status_seq;
+drop table pm_task_status cascade;
+
+drop table pm_tasks cascade;
+drop table pm_tasks_revisions cascade;
+
+select content_type__drop_type('pm_task', 't', 'f');
+
+select content_type__drop_type('pm_project', 't', 'f');
+
+drop table pm_task_xref cascade;
+drop table pm_users_viewed cascade;
+drop sequence pm_process_instance_seq;
+drop table pm_process_instance cascade;
+drop table pm_process cascade;
+-- note that the Project Repository folder is not deleted
+
Index: openacs-4/packages/project-manager/sql/postgresql/project-manager-functions-create.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/sql/postgresql/project-manager-functions-create.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/sql/postgresql/project-manager-functions-create.sql 29 Apr 2005 17:43:36 -0000 1.1
@@ -0,0 +1,641 @@
+--
+-- packages/project-manager/sql/postgresql/project-manager-functions-create.sql
+--
+-- @author jade@bread.com, ncarroll@ee.usyd.edu.au
+-- @creation-date 2003-05-15
+-- @cvs-id $Id: project-manager-functions-create.sql,v 1.1 2005/04/29 17:43:36 timoh Exp $
+--
+--
+
+-- When we created the acs object type above, we specified a
+-- 'name_method'. This is the name of a function that will return the
+-- name of the object. This is a convention ensuring that all objects
+-- can be identified. Now we have to build that function. In this case,
+-- we'll return a field called title as the name.
+
+select define_function_args('pm_project__name', 'project_id');
+
+create or replace function pm_project__name (integer)
+returns varchar as '
+declare
+ p_pm_project_id alias for $1;
+ v_pm_project_name pm_projectsx.name%TYPE;
+begin
+ select name || ''_'' || p_pm_project_id into v_pm_project_name
+ from pm_projectsx
+ where item_id = p_pm_project_id;
+ return v_pm_project_name;
+end;
+' language 'plpgsql';
+
+
+-- Create a new root folder
+
+select define_function_args('pm_project__new_root_folder', 'package_id');
+
+create or replace function pm_project__new_root_folder (integer)
+returns integer as '
+declare
+ p_package_id alias for $1;
+
+ v_folder_id cr_folders.folder_id%TYPE;
+ v_folder_name cr_items.name%TYPE;
+begin
+
+ -- raise notice ''in new root folder'';
+
+ -- Set the folder name
+ v_folder_name := pm_project__new_unique_name (p_package_id);
+
+ v_folder_id := content_folder__new (
+ v_folder_name, -- name
+ ''Projects'', -- label
+ ''Project Repository'', -- description
+ null, -- parent_id
+ p_package_id, -- context_id
+ null, -- folder_id
+ null, -- creation_date
+ null, -- creation_user
+ null -- creation_ip
+ );
+
+ -- Register the standard content types
+ PERFORM content_folder__register_content_type (
+ v_folder_id, -- folder_id
+ ''pm_project'', -- content_type
+ ''f'' -- include_subtypes
+ );
+
+ -- there is no facility in the API for adding in the package_id,
+ -- so we have to do it ourselves
+
+ update cr_folders
+ set package_id = p_package_id
+ where folder_id = v_folder_id;
+
+ -- TODO: Handle Permissions here for this folder.
+
+ return v_folder_id;
+end;' language 'plpgsql';
+
+
+-- Returns the root folder corresponding to a particular package instance.
+-- Creates a new root folder if one does not exist for the specified package
+-- instance.
+
+select define_function_args('pm_project__get_root_folder', 'package_id,create_if_not_present_p');
+
+create or replace function pm_project__get_root_folder (integer, boolean)
+returns integer as '
+declare
+ p_package_id alias for $1;
+ p_create_if_not_present_p alias for $2;
+
+ v_folder_id cr_folders.folder_id%TYPE;
+ v_count integer;
+begin
+
+ -- raise notice ''in get root folder p_create_if_not_present_p = %'',p_create_if_not_present_p;
+
+ select count(*) into v_count
+ from cr_folders
+ where package_id = p_package_id;
+
+ -- raise notice ''count is % for package_id %'', v_count, p_package_id;
+
+ if v_count > 1 then
+ raise exception ''More than one project repository for this application instance'';
+ elsif v_count = 1 then
+ select folder_id into v_folder_id
+ from cr_folders
+ where package_id = p_package_id;
+ else
+ if p_create_if_not_present_p = true then
+ -- Must be a new instance. Create a new root folder.
+ raise notice ''creating a new root repository folder'';
+ v_folder_id := pm_project__new_root_folder(p_package_id);
+ else
+ -- raise notice ''setting to null'';
+ v_folder_id := null;
+ end if;
+ end if;
+
+ -- raise notice ''v_folder_id is %'', v_folder_id;
+
+ return v_folder_id;
+
+end; ' language 'plpgsql';
+
+
+-- Create a project item.
+
+-- A project item should be placed within a folder. Therefore a new project
+-- item is associated with creating a new project folder that will contain
+-- the project item. A new root project folder will be created if parent_id
+-- is null. Otherwise a project folder will be created as a sub-folder
+-- of an existing project folder.
+
+select define_function_args('pm_project__new_project_item', 'project_name, project_code, parent_id, goal, description, mime_type, planned_start_date, planned_end_date, actual_start_date, actual_end_date, logger_project, ongoing_p, status_id, customer_id, creation_date, creation_user, creation_ip, package_id');
+
+create or replace function pm_project__new_project_item (
+ varchar, -- project_name
+ varchar, -- project_code
+ integer, -- parent_id
+ varchar, -- goal
+ varchar, -- description
+ varchar, -- mime_type
+ timestamptz, -- planned_start_date
+ timestamptz, -- planned_end_date
+ timestamptz, -- actual_start_date
+ timestamptz, -- actual_end_date
+ integer, -- logger_project
+ char(1), -- ongoing_p
+ integer, -- status_id
+ integer, -- customer_id (organization_id)
+ timestamptz, -- creation_date
+ integer, -- creation_user
+ varchar, -- creation_ip
+ integer -- package_id
+) returns integer
+as '
+declare
+ p_project_name alias for $1;
+ p_project_code alias for $2;
+ p_parent_id alias for $3;
+ p_goal alias for $4;
+ p_description alias for $5;
+ p_mime_type alias for $6;
+ p_planned_start_date alias for $7;
+ p_planned_end_date alias for $8;
+ p_actual_start_date alias for $9;
+ p_actual_end_date alias for $10;
+ p_logger_project alias for $11;
+ p_ongoing_p alias for $12;
+ p_status_id alias for $13;
+ p_customer_id alias for $14;
+ p_creation_date alias for $15;
+ p_creation_user alias for $16;
+ p_creation_ip alias for $17;
+ p_package_id alias for $18;
+
+ v_item_id cr_items.item_id%TYPE;
+ v_revision_id cr_revisions.revision_id%TYPE;
+ v_id cr_items.item_id%TYPE;
+ v_parent_id cr_items.parent_id%TYPE;
+begin
+ select acs_object_id_seq.nextval into v_id from dual;
+
+ v_parent_id := pm_project__get_root_folder (p_package_id, ''t'');
+
+ -- raise notice ''v_parent_id (%) p_parent_id (%)'', v_parent_id, p_parent_id;
+
+ if p_parent_id is not null
+ then
+ v_parent_id = p_parent_id;
+ end if;
+
+ -- raise notice ''v_parent_id (%) p_parent_id (%)'', v_parent_id, p_parent_id;
+
+ v_item_id := content_item__new (
+ v_id::varchar, -- name
+ v_parent_id, -- parent_id
+ v_id, -- item_id
+ null, -- locale
+ now(), -- creation_date
+ p_creation_user, -- creation_user
+ p_parent_id, -- context_id
+ p_creation_ip, -- creation_ip
+ ''content_item'', -- item_subtype
+ ''pm_project'', -- content_type
+ p_project_name, -- title
+ p_description, -- description
+ p_mime_type, -- mime_type
+ null, -- nls_language
+ null -- data
+ );
+
+ v_revision_id := content_revision__new (
+ p_project_name, -- title
+ p_description, -- description
+ now(), -- publish_date
+ p_mime_type, -- mime_type
+ NULL, -- nls_language
+ NULL, -- data
+ v_item_id, -- item_id
+ NULL, -- revision_id
+ now(), -- creation_date
+ p_creation_user, -- creation_user
+ p_creation_ip -- creation_ip
+ );
+
+ PERFORM content_item__set_live_revision (v_revision_id);
+
+ insert into pm_projects (
+ project_id, project_code,
+ goal, planned_start_date,
+ planned_end_date, actual_start_date, actual_end_date,
+ logger_project, ongoing_p, estimated_finish_date,
+ earliest_finish_date, latest_finish_date,
+ actual_hours_completed,
+ estimated_hours_total, status_id, customer_id)
+ values (
+ v_revision_id, p_project_code,
+ p_goal, p_planned_start_date,
+ p_planned_end_date, p_actual_start_date,
+ p_actual_end_date, p_logger_project, p_ongoing_p,
+ p_planned_end_date,
+ p_planned_end_date, p_planned_end_date, ''0'',
+ ''0'', p_status_id, p_customer_id
+ );
+
+ PERFORM acs_permission__grant_permission(
+ v_revision_id,
+ p_creation_user,
+ ''admin''
+ );
+
+ return v_revision_id;
+end;' language 'plpgsql';
+
+
+-- The delete function deletes a record and all related overhead.
+
+select define_function_args('pm_project__delete_project_item', 'project_id');
+
+create or replace function pm_project__delete_project_item (integer)
+returns integer as '
+declare
+ p_project_id alias for $1;
+ v_child cr_items%ROWTYPE;
+begin
+ raise NOTICE ''Deleting pm_project...'';
+
+ for v_child in select
+ item_id
+ from
+ cr_items
+ where
+ parent_id = p_project_id and
+ content_type = ''pm_project''
+ LOOP
+ PERFORM pm_project__delete_project_item(v_child.item_id);
+ end loop;
+
+ delete from pm_projects where project_id in (select revision_id from pm_projectsx where item_id = p_project_id);
+
+ PERFORM content_item__delete(p_project_id);
+ return 0;
+end;' language 'plpgsql';
+
+
+select define_function_args('pm_project__new_project_revision', 'item_id, project_name, project_code, parent_id, goal, description, planned_start_date, planned_end_date, actual_start_date, actual_end_date, logger_project, ongoing_p, status_id, organization_id, creation_date, creation_user, creation_ip, package_id');
+
+create or replace function pm_project__new_project_revision (
+ integer, -- item_id
+ varchar, -- project_name
+ varchar, -- project_code
+ integer, -- parent_id
+ varchar, -- goal
+ varchar, -- description
+ timestamptz, -- planned_start_date
+ timestamptz, -- planned_end_date
+ timestamptz, -- actual_start_date
+ timestamptz, -- actual_end_date
+ integer, -- logger_project
+ char(1), -- ongoing_p
+ integer, -- status_id
+ integer, -- organization_id (customer)
+ timestamptz, -- creation_date
+ integer, -- creation_user
+ varchar, -- creation_ip
+ integer -- package_id
+) returns integer
+as '
+declare
+ p_item_id alias for $1;
+ p_project_name alias for $2;
+ p_project_code alias for $3;
+ p_parent_id alias for $4;
+ p_goal alias for $5;
+ p_description alias for $6;
+ p_planned_start_date alias for $7;
+ p_planned_end_date alias for $8;
+ p_actual_start_date alias for $9;
+ p_actual_end_date alias for $10;
+ p_logger_project alias for $11;
+ p_ongoing_p alias for $12;
+ p_status_id alias for $13;
+ p_customer_id alias for $14;
+ p_creation_date alias for $15;
+ p_creation_user alias for $16;
+ p_creation_ip alias for $17;
+ p_package_id alias for $18;
+
+ v_revision_id cr_revisions.revision_id%TYPE;
+begin
+
+ -- the item_id is the project_id
+
+ v_revision_id := content_revision__new (
+ p_project_name, -- title
+ p_description, -- description
+ now(), -- publish_date
+ ''text/plain'', -- mime_type
+ NULL, -- nls_language
+ NULL, -- data
+ p_item_id, -- item_id
+ NULL, -- revision_id
+ now(), -- creation_date
+ p_creation_user, -- creation_user
+ p_creation_ip -- creation_ip
+ );
+
+ PERFORM content_item__set_live_revision (v_revision_id);
+
+ insert into pm_projects (
+ project_id, project_code,
+ goal, planned_start_date,
+ planned_end_date, actual_start_date, actual_end_date,
+ logger_project,
+ ongoing_p, status_id, customer_id)
+ values (
+ v_revision_id, p_project_code,
+ p_goal, p_planned_start_date,
+ p_planned_end_date, p_actual_start_date,
+ p_actual_end_date,
+ p_logger_project, p_ongoing_p, p_status_id, p_customer_id);
+
+ PERFORM acs_permission__grant_permission(
+ v_revision_id,
+ p_creation_user,
+ ''admin''
+ );
+
+ return v_revision_id;
+end;' language 'plpgsql';
+
+
+
+-- Creates and returns a unique name.
+
+select define_function_args('pm_project__new_unique_name', 'package_id');
+
+create or replace function pm_project__new_unique_name (integer)
+returns text as '
+declare
+ p_package_id alias for $1;
+
+ v_name cr_items.name%TYPE;
+ v_package_key apm_packages.package_key%TYPE;
+ v_id integer;
+begin
+ select package_key into v_package_key from apm_packages
+ where package_id = p_package_id;
+
+ select acs_object_id_seq.nextval into v_id from dual;
+
+ -- Set the name
+ select v_package_key || ''_'' ||
+ to_char(current_timestamp, ''YYYYMMDD'') || ''_'' ||
+ v_id into v_name;
+
+ return v_name;
+end;' language 'plpgsql';
+
+----------------------------------
+-- Tasks
+----------------------------------
+
+-- When we created the acs object type above, we specified a
+-- 'name_method'. This is the name of a function that will return the
+-- name of the object. This is a convention ensuring that all objects
+-- can be identified. Now we have to build that function. In this case,
+-- we'll return a field called title as the name.
+
+select define_function_args('pm_task__name', 'task_id');
+
+create or replace function pm_task__name (integer)
+returns varchar as '
+declare
+ p_pm_task_id alias for $1;
+ v_pm_task_name cr_items.name%TYPE;
+begin
+ select i.name || ''_'' || p_pm_task_id into v_pm_task_name
+ from cr_items i
+ where i.item_id = p_pm_task_id;
+ return v_pm_task_name;
+end;
+' language 'plpgsql';
+
+
+-- Create a task item.
+
+-- A task should be placed within a project or another task.
+-- If it is not associated with a project, then it is placed in the root
+-- project repository folder.
+
+select define_function_args('pm_task__new_task_item', 'project_id, title, description, html_p, end_date, percent_complete, estimated_hours_work, estimated_hours_work_min, estimated_hours_work_max, status_id, process_instance_id, creation_date, creation_user, creation_ip, package_id, priority');
+
+create or replace function pm_task__new_task_item (
+ integer, -- project_id
+ varchar, -- title
+ varchar, -- description
+ varchar, -- html_p
+ timestamptz, -- end_date
+ numeric, -- percent_complete
+ numeric, -- estimated_hours_work
+ numeric, -- estimated_hours_work_min
+ numeric, -- estimated_hours_work_max,
+ integer, -- status_id
+ integer, -- process_instance_id
+ timestamptz, -- creation_date
+ integer, -- creation_user
+ varchar, -- creation_ip
+ integer, -- package_id
+ integer -- priority
+) returns integer
+as '
+declare
+ p_project_id alias for $1;
+ p_title alias for $2;
+ p_description alias for $3;
+ p_mime_type alias for $4;
+ p_end_date alias for $5;
+ p_percent_complete alias for $6;
+ p_estimated_hours_work alias for $7;
+ p_estimated_hours_work_min alias for $8;
+ p_estimated_hours_work_max alias for $9;
+ p_status_id alias for $10;
+ p_process_instance_id alias for $11;
+ p_creation_date alias for $12;
+ p_creation_user alias for $13;
+ p_creation_ip alias for $14;
+ p_package_id alias for $15;
+ p_priority alias for $16;
+
+ v_item_id cr_items.item_id%TYPE;
+ v_revision_id cr_revisions.revision_id%TYPE;
+ v_id cr_items.item_id%TYPE;
+ v_task_number integer;
+begin
+ select acs_object_id_seq.nextval into v_id from dual;
+
+ -- We want to put the task under the project item
+
+ -- create the task_number
+
+ v_item_id := content_item__new (
+ v_id::varchar, -- name
+ p_project_id, -- parent_id
+ v_id, -- item_id
+ null, -- locale
+ now(), -- creation_date
+ p_creation_user, -- creation_user
+ p_package_id, -- context_id
+ p_creation_ip, -- creation_ip
+ ''content_item'', -- item_subtype
+ ''pm_task'', -- content_type
+ p_title, -- title
+ p_description, -- description
+ p_mime_type, -- mime_type
+ null, -- nls_language
+ null -- data
+ );
+
+ v_revision_id := content_revision__new (
+ p_title, -- title
+ p_description, -- description
+ now(), -- publish_date
+ p_mime_type, -- mime_type
+ NULL, -- nls_language
+ NULL, -- data
+ v_item_id, -- item_id
+ NULL, -- revision_id
+ now(), -- creation_date
+ p_creation_user, -- creation_user
+ p_creation_ip -- creation_ip
+ );
+
+ PERFORM content_item__set_live_revision (v_revision_id);
+
+ insert into pm_tasks (
+ task_id, task_number, status, process_instance)
+ values (
+ v_item_id, v_task_number, p_status_id, p_process_instance_id);
+
+ insert into pm_tasks_revisions (
+ task_revision_id, end_date, percent_complete, estimated_hours_work, estimated_hours_work_min, estimated_hours_work_max, actual_hours_worked, priority)
+ values (
+ v_revision_id, p_end_date, p_percent_complete, p_estimated_hours_work, p_estimated_hours_work_min, p_estimated_hours_work_max, ''0'', p_priority);
+
+ PERFORM acs_permission__grant_permission(
+ v_revision_id,
+ p_creation_user,
+ ''admin''
+ );
+
+ return v_revision_id;
+end;' language 'plpgsql';
+
+
+select define_function_args('pm_task__new_task_revision', 'task_id, project_id, title, description, mime_type, end_date, percent_complete, estimated_hours_work, estimated_hours_work_min, estimated_hours_work_max, actual_hours_worked, creation_date, creation_user, creation_ip, package_id, priority');
+
+create or replace function pm_task__new_task_revision (
+ integer, -- task_id (the item_id)
+ integer, -- project_id
+ varchar, -- title
+ varchar, -- description
+ varchar, -- mime_type
+ timestamptz, -- end_date
+ numeric, -- percent_complete
+ numeric, -- estimated_hours_work
+ numeric, -- estimated_hours_work_min
+ numeric, -- estimated_hours_work_max
+ numeric, -- actual_hours_worked
+ integer, -- status_id
+ timestamptz, -- creation_date
+ integer, -- creation_user
+ varchar, -- creation_ip
+ integer, -- package_id
+ integer -- priority
+) returns integer
+as '
+declare
+ p_task_id alias for $1;
+ p_project_id alias for $2;
+ p_title alias for $3;
+ p_description alias for $4;
+ p_mime_type alias for $5;
+ p_end_date alias for $6;
+ p_percent_complete alias for $7;
+ p_estimated_hours_work alias for $8;
+ p_estimated_hours_work_min alias for $9;
+ p_estimated_hours_work_max alias for $10;
+ p_actual_hours_worked alias for $11;
+ p_status_id alias for $12;
+ p_creation_date alias for $13;
+ p_creation_user alias for $14;
+ p_creation_ip alias for $15;
+ p_package_id alias for $16;
+ p_priority alias for $17;
+ v_revision_id cr_revisions.revision_id%TYPE;
+ v_id cr_items.item_id%TYPE;
+begin
+ select acs_object_id_seq.nextval into v_id from dual;
+
+ -- We want to put the task under the project item
+ update cr_items set parent_id = p_project_id where item_id = p_task_id;
+
+ v_revision_id := content_revision__new (
+ p_title, -- title
+ p_description, -- description
+ now(), -- publish_date
+ p_mime_type, -- mime_type
+ NULL, -- nls_language
+ NULL, -- data
+ p_task_id, -- item_id
+ NULL, -- revision_id
+ now(), -- creation_date
+ p_creation_user, -- creation_user
+ p_creation_ip -- creation_ip
+ );
+
+ PERFORM content_item__set_live_revision (v_revision_id);
+
+ insert into pm_tasks_revisions (
+ task_revision_id, end_date, percent_complete, estimated_hours_work, estimated_hours_work_min, estimated_hours_work_max, actual_hours_worked, priority)
+ values (
+ v_revision_id, p_end_date, p_percent_complete, p_estimated_hours_work, p_estimated_hours_work_min, p_estimated_hours_work_max, p_actual_hours_worked, p_priority);
+
+ update pm_tasks set status = p_status_id where task_id = p_task_id;
+
+ PERFORM acs_permission__grant_permission(
+ v_revision_id,
+ p_creation_user,
+ ''admin''
+ );
+
+ return v_revision_id;
+end;' language 'plpgsql';
+
+
+-- The delete function deletes a record and all related overhead.
+
+select define_function_args('pm_task__delete_task_item', 'task_id');
+
+create or replace function pm_task__delete_task_item (integer)
+returns integer as '
+declare
+ p_task_id alias for $1;
+begin
+ delete from pm_tasks_revisions
+ where task_revision_id in (select revision_id from pm_tasks_revisionsx where item_id = p_task_id);
+
+ delete from pm_tasks
+ where task_id = p_task_id;
+
+ raise NOTICE ''Deleting pm_task...'';
+
+ PERFORM content_item__delete(p_task_id);
+ return 0;
+end;' language 'plpgsql';
Index: openacs-4/packages/project-manager/sql/postgresql/project-manager-notifications-create.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/sql/postgresql/project-manager-notifications-create.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/sql/postgresql/project-manager-notifications-create.sql 29 Apr 2005 17:43:36 -0000 1.1
@@ -0,0 +1,70 @@
+-- Following directions at
+-- http://openacs.org/doc/openacs-HEAD/tutorial-notifications.html
+
+-- using pm_task_notif_type instead of lars_blogger_notif_type
+-- using project-manager instead of lars-blogger
+
+create function inline_0() returns integer as '
+declare
+ impl_id integer;
+ v_foo integer;
+begin
+ -- the notification type impl
+ impl_id := acs_sc_impl__new (
+ ''NotificationType'',
+ ''pm_task_notif_type'',
+ ''project-manager''
+ );
+
+ v_foo := acs_sc_impl_alias__new (
+ ''NotificationType'',
+ ''pm_task_notif_type'',
+ ''GetURL'',
+ ''pm::task::get_url'',
+ ''TCL''
+ );
+
+ v_foo := acs_sc_impl_alias__new (
+ ''NotificationType'',
+ ''pm_task_notif_type'',
+ ''ProcessReply'',
+ ''pm::task::process_reply'',
+ ''TCL''
+ );
+
+ PERFORM acs_sc_binding__new (
+ ''NotificationType'',
+ ''pm_task_notif_type''
+ );
+
+ v_foo:= notification_type__new (
+ NULL,
+ impl_id,
+ ''pm_task_notif'',
+ ''Task Notification'',
+ ''Notifications of task changes'',
+ now(),
+ NULL,
+ NULL,
+ NULL
+ );
+
+ -- enable the various intervals and delivery methods
+ insert into notification_types_intervals
+ (type_id, interval_id)
+ select v_foo, interval_id
+ from notification_intervals where name in (''instant'',''hourly'',''daily'');
+
+ insert into notification_types_del_methods
+ (type_id, delivery_method_id)
+ select v_foo, delivery_method_id
+ from notification_delivery_methods where short_name in (''email'');
+
+
+ return (0);
+end;
+' language 'plpgsql';
+
+
+select inline_0();
+drop function inline_0();
Index: openacs-4/packages/project-manager/sql/postgresql/project-manager-notifications-drop.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/sql/postgresql/project-manager-notifications-drop.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/sql/postgresql/project-manager-notifications-drop.sql 29 Apr 2005 17:43:37 -0000 1.1
@@ -0,0 +1,92 @@
+--
+-- Project Manager
+--
+-- @author jader@bread.com
+-- @author gwong@orchardlabs.com,ben@openforce.biz
+-- @creation-date 2002-05-16
+--
+-- This code is newly concocted by Ben, but with significant concepts and code
+-- lifted from Gilbert's UBB forums. Thanks Orchard Labs.
+-- Jade in turn lifted this from gwong and ben.
+--
+
+create function inline_0 ()
+returns integer as '
+declare
+ row record;
+begin
+ for row in select nt.type_id
+ from notification_types nt
+ where nt.short_name in (''pm_task_notif'')
+ loop
+ perform notification_type__delete(row.type_id);
+ end loop;
+
+ return null;
+end;' language 'plpgsql';
+
+select inline_0();
+drop function inline_0 ();
+
+--
+-- Service contract drop stuff was missing - Roberto Mello
+--
+
+create function inline_0() returns integer as '
+declare
+ impl_id integer;
+ v_foo integer;
+begin
+
+ -- the notification type impl
+ impl_id := acs_sc_impl__get_id (
+ ''NotificationType'', -- impl_contract_name
+ ''pm_task_notif_type'' -- impl_name
+ );
+
+ PERFORM acs_sc_binding__delete (
+ ''NotificationType'',
+ ''pm_task_notif_type''
+ );
+
+ v_foo := acs_sc_impl_alias__delete (
+ ''NotificationType'', -- impl_contract_name
+ ''pm_task_notif_type'', -- impl_name
+ ''GetURL'' -- impl_operation_name
+ );
+
+ v_foo := acs_sc_impl_alias__delete (
+ ''NotificationType'', -- impl_contract_name
+ ''pm_task_notif_type'', -- impl_name
+ ''ProcessReply'' -- impl_operation_name
+ );
+
+ select into v_foo type_id
+ from notification_types
+ where sc_impl_id = impl_id
+ and short_name = ''pm_task_notif'';
+
+ perform notification_type__delete (v_foo);
+
+ delete from notification_types_intervals
+ where type_id = v_foo
+ and interval_id in (
+ select interval_id
+ from notification_intervals
+ where name in (''instant'',''hourly'',''daily'')
+ );
+
+ delete from notification_types_del_methods
+ where type_id = v_foo
+ and delivery_method_id in (
+ select delivery_method_id
+ from notification_delivery_methods
+ where short_name in (''email'')
+ );
+
+ return (0);
+end;
+' language 'plpgsql';
+
+select inline_0();
+drop function inline_0();
Index: openacs-4/packages/project-manager/sql/postgresql/project-manager-table-create.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/sql/postgresql/project-manager-table-create.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/sql/postgresql/project-manager-table-create.sql 29 Apr 2005 17:43:37 -0000 1.1
@@ -0,0 +1,673 @@
+-- packages/project-manager/sql/postgresql/project-manager-table-create.sql
+--
+-- @author jader@bread.com
+-- @author ncarroll@ee.usyd.edu.au was involved in creating the initial CR version
+-- @author everyone else involved in this thread: http://openacs.org/forums/message-view?message_id=90742
+-- @creation-date 2003-05-15
+--
+
+-- PROJECTS
+
+create sequence pm_project_status_seq start 3;
+
+create table pm_project_status (
+ status_id integer
+ constraint pm_project_status_pk
+ primary key,
+ description varchar(100),
+ -- closed or open
+ status_type char(1) default 'c'
+ constraint pm_projects_status_type_ck
+ check (status_type in ('c','o'))
+);
+
+insert into pm_project_status (status_id, description, status_type) values
+(1, 'Open', 'o');
+insert into pm_project_status (status_id, description, status_type) values
+(2, 'Closed', 'c');
+
+
+-- project revisions, items are kept in cr_items
+
+create table pm_projects (
+ project_id integer
+ constraint pm_proj_rev_fk
+ references cr_revisions on delete cascade
+ constraint pm_proj_rev_pk
+ primary key,
+ -- a user-specified project code
+ project_code varchar(255),
+ goal varchar(4000),
+ planned_start_date timestamptz,
+ planned_end_date timestamptz,
+ actual_start_date timestamptz,
+ actual_end_date timestamptz,
+ status_id integer
+ constraint pm_projects_status_id_nn
+ not null
+ constraint pm_projects_status_id_fk
+ references pm_project_status,
+ -- if ongoing_p is true, then actual_end_date must be null
+ ongoing_p char(1) default 'f'
+ constraint pm_projects_ongoing_p_ck
+ check (ongoing_p in ('t','f')),
+ estimated_finish_date timestamptz,
+ earliest_finish_date timestamptz,
+ latest_finish_date timestamptz,
+ -- denormalized, taken from logger
+ actual_hours_completed numeric,
+ estimated_hours_total numeric,
+ -- The logger package keeps its own projects table
+ logger_project integer
+ constraint pm_projects_logger_pj_nn
+ not null
+ constraint pm_projects_logger_pj_fk
+ references logger_projects
+);
+
+
+-- create the content type
+ select content_type__create_type (
+ 'pm_project', -- content_type
+ 'content_revision', -- supertype
+ 'Project', -- pretty_name
+ 'Projects', -- pretty_plural
+ 'pm_projects', -- table_name
+ 'project_id', -- id_column
+ 'pm_project__name' -- name_method
+ );
+
+
+-- other fields are added in too. See the -custom script.
+
+
+-- ROLES
+
+create sequence pm_role_seq start 4;
+
+create table pm_roles (
+ role_id integer
+ constraint pm_role_id_pk
+ primary key,
+ one_line varchar(100)
+ constraint pm_role_one_line_uq
+ unique,
+ description varchar(2000),
+ sort_order integer,
+ is_observer_p char(1) default 'f'
+ constraint pm_role_is_observer_ck
+ check (is_observer_p in ('t','f')),
+ is_lead_p char(1) default 'f'
+ constraint pm_role_is_lead_ck
+ check (is_lead_p in ('t','f'))
+);
+
+
+comment on table pm_roles is '
+ Roles represent the way in which a party participates in a project
+ or task. For example, they could be a manager, or client, or
+ participant.. The sort order determines what order it is displayed
+ in. The is_observer_p specifies whether they are directly
+ responsible for the task, or are just observers on it.
+';
+
+insert into pm_roles (role_id, one_line, description, sort_order, is_lead_p) values ('1','Lead','Team members who are responsible for the completion of the project','10','t');
+insert into pm_roles (role_id, one_line, description, sort_order) values ('2','Player','A person on the team responsible for completion of the project','20');
+insert into pm_roles (role_id, one_line, description, sort_order, is_observer_p) values ('3','Watcher','A person interested in developments, possibly helping out on it.','30','t');
+
+
+create table pm_default_roles (
+ role_id integer
+ constraint pm_default_role_fk
+ references pm_roles
+ on delete cascade,
+ party_id integer
+ constraint pm_default_role_party_fk
+ references parties(party_id)
+ on delete cascade,
+ constraint pm_default_roles_uq
+ unique (role_id, party_id)
+);
+
+comment on table pm_default_roles is '
+ Specifies what role a person is a part of by default
+';
+
+-- PROJECT ASSIGNMENT
+
+create table pm_project_assignment (
+ project_id integer
+ constraint pm_proj_role_map_project_fk
+ references cr_items
+ on delete cascade,
+ role_id integer
+ constraint pm_project_role_map_role_fk
+ references pm_roles,
+ party_id integer
+ constraint pm_project_role_map_user_id_fk
+ references parties(party_id)
+ on delete cascade,
+ constraint pm_project_assignment_uq
+ unique (project_id, role_id, party_id)
+);
+
+
+comment on table pm_project_assignment is '
+ Maps who is a part of what project, and in what capacity
+';
+
+
+-- PROCESSES
+
+create sequence pm_process_seq;
+
+create table pm_process (
+ process_id integer
+ constraint pm_process_id_pk
+ primary key,
+ one_line varchar(200)
+ constraint pm_process_one_line_nn
+ not null,
+ description varchar(1000),
+ party_id integer
+ constraint pm_process_party_fk
+ references parties
+ constraint pm_process_party_nn
+ not null,
+ creation_date timestamptz,
+ deleted_p char(1) default 'f'
+ constraint pm_process_deleted_p_ck
+ check (deleted_p in ('t','f'))
+);
+
+comment on table pm_process is '
+ Processes are a set of templates for tasks, so that people can
+ create sets of tasks quickly. Their structure needs to match that of
+ tasks. The process holds the meta information, and is also an identifier
+ that is used by the user to select which process they''d like to copy or
+ use
+';
+
+create or replace view
+pm_process_active as
+ SELECT * FROM pm_process where deleted_p = 'f';
+
+-- each time a process is used, it creates an instance of that process
+-- we use this to allow a user to see overviews of process status, etc..
+
+create sequence pm_process_instance_seq start 1;
+
+create table pm_process_instance (
+ instance_id integer
+ constraint pm_process_instance_id_pk
+ primary key,
+ name varchar(200),
+ process_id integer
+ constraint pm_process_instance_process_fk
+ references pm_process on delete cascade,
+ project_item_id integer
+ constraint pm_process_project_fk
+ references cr_items
+);
+
+
+create sequence pm_process_task_seq;
+
+create table pm_process_task (
+ process_task_id integer
+ constraint pm_process_task_id_pk
+ primary key,
+ process_id integer
+ constraint pm_process_process_id_fk
+ references
+ pm_process
+ constraint pm_process_process_id_nn
+ not null,
+ one_line varchar(200)
+ constraint pm_process_task_one_line_nn
+ not null,
+ description varchar(4000),
+ mime_type varchar(200)
+ constraint pm_process_task_mime_type_fk
+ references cr_mime_types(mime_type)
+ on update no action on delete no action
+ default 'text/plain',
+ -- dates are optional, because it may be computed in reference
+ -- to all other items, or simply not have a deadline
+ -- percent complete is always 0
+ estimated_hours_work numeric,
+ -- PERT charts require minimum and maximum estimates
+ -- these are optionally used
+ estimated_hours_work_min numeric,
+ estimated_hours_work_max numeric,
+ ordering integer
+);
+
+comment on table pm_process_task is '
+ A template for the tasks that will be created by the process
+';
+
+-- DEPENDENCIES
+
+-- dependency types
+-- such as:
+-- cannot start until Task X finishes
+-- cannot start until Task X begins
+-- cannot finish until Task X finishes
+-- cannot finish until Task X begins
+
+create table pm_task_dependency_types (
+ short_name varchar(100)
+ constraint pm_task_const_sn_pk
+ primary key,
+ description varchar(1000)
+);
+
+insert into pm_task_dependency_types (short_name, description) values ('start_before_start','Starts before this starts');
+insert into pm_task_dependency_types (short_name, description) values ('start_before_finish','Starts before this finishes');
+insert into pm_task_dependency_types (short_name, description) values ('finish_before_start','Finishes before this starts');
+insert into pm_task_dependency_types (short_name, description) values ('finish_before_finish','Finishes before this finishes');
+
+create sequence pm_process_task_dependency_seq;
+
+create table pm_process_task_dependency (
+ dependency_id integer
+ constraint pm_proc_task_dependcy_pk
+ primary key,
+ process_task_id integer
+ constraint pm_proc_task_proc_task_fk
+ references pm_process_task
+ on delete cascade,
+ parent_task_id integer
+ constraint pm_proc_task_parent_id_fk
+ references pm_process_task
+ on delete cascade,
+ dependency_type varchar
+ constraint pm_process_task_dep_type
+ references pm_task_dependency_types,
+ constraint pm_proc_task_depend_uq
+ unique (process_task_id, parent_task_id)
+);
+
+comment on table pm_process_task_dependency is '
+ Keeps track of dependencies. Used to create the dependencies in the
+ new tasks.
+';
+
+create table pm_process_task_assignment (
+ process_task_id integer
+ constraint pm_proc_task_assign_task_fk
+ references pm_process_task(process_task_id)
+ on delete cascade,
+ role_id integer
+ constraint pm_task_assignment_role_fk
+ references pm_roles,
+ party_id integer
+ constraint pm_task_assignment_party_fk
+ references parties(party_id)
+ on delete cascade,
+ constraint pm_proc_task_assgn_uq
+ unique (process_task_id, role_id, party_id)
+);
+
+
+comment on table pm_process_task_assignment is '
+ Maps who is assigned to process tasks. These will be the default people
+ assigned to the new tasks
+';
+
+
+
+-- TASKS
+
+-- we create two tables to store task information
+-- the information that we keep revisions on is in the
+-- pm_task_revisions table, the rest is in pm_task
+
+create sequence pm_task_status_seq start 3;
+
+create table pm_task_status (
+ status_id integer
+ constraint pm_task_status_pk
+ primary key,
+ description varchar(100),
+ -- closed or open
+ status_type char(1) default 'c'
+ constraint pm_task_status_type_ck
+ check (status_type in ('c','o'))
+);
+
+insert into pm_task_status (status_id, description, status_type) values
+(1, 'Open', 'o');
+insert into pm_task_status (status_id, description, status_type) values
+(2, 'Closed', 'c');
+
+
+create sequence pm_tasks_number_seq;
+
+create table pm_tasks (
+ task_id integer
+ constraint pm_tasks_task_id_fk
+ references cr_items
+ on delete cascade
+ constraint pm_task_task_id_pk
+ primary key,
+ task_number integer,
+ status integer
+ constraint pm_tasks_task_status_fk
+ references pm_task_status,
+ deleted_p char(1) default 'f'
+ constraint pm_tasks_deleted_p_ck
+ check (deleted_p in ('t','f')),
+ process_instance integer
+ constraint pm_tasks_process_instance_fk
+ references
+ pm_process_instance
+);
+
+CREATE OR REPLACE view
+pm_tasks_active as
+ SELECT task_id, task_number, status, process_instance FROM pm_tasks where deleted_p = 'f';
+
+
+create table pm_tasks_revisions (
+ task_revision_id integer
+ constraint pm_task_revs_id_fk
+ references cr_revisions
+ on delete cascade
+ constraint pm_task_revs_id_pk
+ primary key,
+ -- dates are optional, because it may be computed in reference
+ -- to all other items, or simply not have a deadline
+ end_date timestamptz,
+ -- keep track of completion status
+ percent_complete numeric
+ constraint pm_task_per_complete_gt_ck
+ check(percent_complete >= 0)
+ constraint pm_task_per_complete_lt_ck
+ check(percent_complete <= 100),
+ estimated_hours_work numeric,
+ -- PERT charts require minimum and maximum estimates
+ -- these are optionally used
+ estimated_hours_work_min numeric,
+ estimated_hours_work_max numeric,
+ -- this should be computed by checking with logger? The actual
+ -- data should be in logger, logged by who did it, when etc..
+ -- or we can create a separate table to keep track of task hours
+ -- and make sure its data model is similar to logger?
+ actual_hours_worked numeric,
+ -- network diagram stuff, computed
+ earliest_start timestamptz,
+ earliest_finish timestamptz,
+ latest_start timestamptz,
+ latest_finish timestamptz,
+ -- How important is this task
+ priority integer default 0
+);
+
+-- create the content type
+select content_type__create_type (
+ 'pm_task', -- content_type
+ 'content_revision', -- supertype
+ 'Task', -- pretty_name
+ 'Tasks', -- pretty_plural
+ 'pm_tasks_revisions', -- table_name (should this be pm_task?)
+ 'task_revision_id', -- id_column
+ 'pm_task__name' -- name_method
+);
+
+-- add in attributes
+
+select content_type__create_attribute (
+ 'pm_task', -- content_type
+ 'end_date', -- attribute_name
+ 'date', -- datatype
+ 'End date', -- pretty_name
+ 'End dates', -- pretty_plural
+ null, -- sort_order
+ null, -- default value
+ 'timestamptz' -- column_spec
+);
+
+select content_type__create_attribute (
+ 'pm_task', -- content_type
+ 'percent_complete', -- attribute_name
+ 'number', -- datatype
+ 'Percent complete', -- pretty_name
+ 'Percents complete', -- pretty_plural
+ null, -- sort_order
+ null, -- default value
+ 'numeric' -- column_spec
+);
+
+select content_type__create_attribute (
+ 'pm_task', -- content_type
+ 'estimated_hours_work', -- attribute_name
+ 'number', -- datatype
+ 'Estimated hours work', -- pretty_name
+ 'Estimated hours work', -- pretty_plural
+ null, -- sort_order
+ null, -- default value
+ 'numeric' -- column_spec
+);
+
+select content_type__create_attribute (
+ 'pm_task', -- content_type
+ 'estimated_hours_work_min', -- attribute_name
+ 'number', -- datatype
+ 'Estimated minimum hours', -- pretty_name
+ 'Estimated minimum hours', -- pretty_plural
+ null, -- sort_order
+ null, -- default value
+ 'numeric' -- column_spec
+);
+
+select content_type__create_attribute (
+ 'pm_task', -- content_type
+ 'estimated_hours_work_max', -- attribute_name
+ 'number', -- datatype
+ 'Estimated maximum hours', -- pretty_name
+ 'Estimated maximum hours', -- pretty_plural
+ null, -- sort_order
+ null, -- default value
+ 'numeric' -- column_spec
+);
+
+select content_type__create_attribute (
+ 'pm_task', -- content_type
+ 'actual_hours_worked', -- attribute_name
+ 'number', -- datatype
+ 'Actual hours worked', -- pretty_name
+ 'Actual hours worked', -- pretty_plural
+ null, -- sort_order
+ null, -- default value
+ 'numeric' -- column_spec
+);
+
+select content_type__create_attribute (
+ 'pm_task', -- content_type
+ 'earliest_start', -- attribute_name
+ 'date', -- datatype
+ 'Earliest start date', -- pretty_name
+ 'Earliest start dates', -- pretty_plural
+ null, -- sort_order
+ null, -- default value
+ 'timestamptz' -- column_spec
+);
+
+select content_type__create_attribute (
+ 'pm_task', -- content_type
+ 'earliest_finish', -- attribute_name
+ 'date', -- datatype
+ 'Earliest finish date', -- pretty_name
+ 'Earliest finish dates', -- pretty_plural
+ null, -- sort_order
+ null, -- default value
+ 'timestamptz' -- column_spec
+);
+
+select content_type__create_attribute (
+ 'pm_task', -- content_type
+ 'latest_start', -- attribute_name
+ 'date', -- datatype
+ 'Latest start date', -- pretty_name
+ 'Latest start dates', -- pretty_plural
+ null, -- sort_order
+ null, -- default value
+ 'timestamptz' -- column_spec
+);
+
+select content_type__create_attribute (
+ 'pm_task', -- content_type
+ 'latest_finish', -- attribute_name
+ 'date', -- datatype
+ 'Latest finish date', -- pretty_name
+ 'Latest finish dates', -- pretty_plural
+ null, -- sort_order
+ null, -- default value
+ 'timestamptz' -- column_spec
+);
+
+
+
+create table pm_task_logger_proj_map (
+ task_item_id integer
+ constraint pm_task_log_proj_map_t_nn
+ not null
+ constraint pm_task_log_proj_map_t_fk
+ references pm_tasks
+ on delete cascade,
+ logger_entry integer
+ constraint pm_task_log_proj_map_l_nn
+ not null
+ constraint pm_task_log_proj_map_l_fk
+ references logger_entries
+ on delete cascade,
+ constraint pm_task_logger_proj_map_uq
+ unique (task_item_id, logger_entry)
+);
+
+
+
+
+create sequence pm_task_dependency_seq;
+
+create table pm_task_dependency (
+ dependency_id integer
+ constraint pm_task_const_id_pk
+ primary key,
+ task_id integer
+ constraint pm_task_const_task_id_nn
+ not null
+ constraint pm_task_const_task_id_fk
+ references pm_tasks
+ on delete cascade,
+ parent_task_id integer
+ constraint pm_tasks_const_parent_id_nn
+ not null
+ constraint pm_tasks_const_parent_id_fk
+ references pm_tasks
+ on delete cascade,
+ dependency_type varchar
+ constraint pm_tasks_const_type_nn
+ not null
+ constraint pm_tasks_const_type_fk
+ references pm_task_dependency_types,
+ constraint pm_task_dependency_uq
+ unique (task_id, parent_task_id)
+);
+
+
+-- WORKGROUPS: currently not used
+
+create sequence pm_workgroup_seq;
+
+create table pm_workgroup (
+ workgroup_id integer
+ constraint pm_workgroup_id_pk
+ primary key,
+ one_line varchar(100)
+ constraint pm_workgroup_one_line_uq
+ unique,
+ description varchar(2000),
+ sort_order integer
+);
+
+create table pm_workgroup_parties (
+ workgroup_id integer
+ constraint pm_workgroup_parties_wg_id_fk
+ references pm_workgroup(workgroup_id)
+ on delete cascade,
+ party_id integer
+ constraint pm_workgroup_party_fk
+ references parties(party_id)
+ on delete cascade,
+ role_id integer
+ constraint pm_workgroup_role_id
+ references pm_roles,
+ constraint pm_workgroup_parties_uq
+ unique (workgroup_id, party_id, role_id)
+);
+
+
+-- TASK ASSIGNMENTS
+
+create table pm_task_assignment (
+ task_id integer
+ constraint pm_task_assignment_task_fk
+ references pm_tasks(task_id)
+ on delete cascade,
+ role_id integer
+ constraint pm_task_assignment_role_fk
+ references pm_roles,
+ party_id integer
+ constraint pm_task_assignment_party_fk
+ references parties(party_id)
+ on delete cascade,
+ constraint pm_task_assignment_uq
+ unique (task_id, role_id, party_id)
+);
+
+
+comment on table pm_task_assignment is '
+ Maps who is a part of what task, and in what capacity
+';
+
+-- TASK CROSS REFERENCES
+
+create table pm_task_xref (
+ task_id_1 integer
+ constraint pm_task_xref_task1_nn
+ not null
+ constraint pm_task_xref_task1_fk
+ references pm_tasks(task_id)
+ on delete cascade,
+ task_id_2 integer
+ constraint pm_task_xref_task2_nn
+ not null
+ constraint pm_task_xref_task2_fk
+ references pm_tasks(task_id)
+ on delete cascade,
+ constraint pm_task_xref_lt check (task_id_1 < task_id_2)
+);
+
+comment on table pm_task_xref is '
+ Maps related tasks.
+';
+
+
+create table pm_users_viewed (
+ viewing_user integer constraint
+ pm_users_viewed_viewing_user_fk
+ references parties,
+ viewed_user integer constraint
+ pm_users_viewed_viewed_user_fk
+ references parties
+);
+
+comment on table pm_users_viewed is '
+ Used to keep track of what users to see on the task calendar and other
+ views.
+';
+
+\i project-manager-custom-create.sql
Index: openacs-4/packages/project-manager/sql/postgresql/upgrade/upgrade-1.02-1.03.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/sql/postgresql/upgrade/upgrade-1.02-1.03.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/sql/postgresql/upgrade/upgrade-1.02-1.03.sql 29 Apr 2005 17:43:37 -0000 1.1
@@ -0,0 +1,87 @@
+--
+-- Upgrade script for project-manager 1.03
+--
+-- @author Jade Rubick (jader@bread.com)
+-- @creation-date 2004-05-14
+-- @cvs-id $Id: upgrade-1.02-1.03.sql,v 1.1 2005/04/29 17:43:37 timoh Exp $
+--
+
+-- the only change in this function is to change the project when
+-- editing tasks. Previously, it would always leave the task in the
+-- same project.
+
+create or replace function pm_task__new_task_revision (
+ integer, -- task_id (the item_id)
+ integer, -- project_id
+ varchar, -- title
+ varchar, -- description
+ varchar, -- mime_type
+ timestamptz, -- end_date
+ numeric, -- percent_complete
+ numeric, -- estimated_hours_work
+ numeric, -- estimated_hours_work_min
+ numeric, -- estimated_hours_work_max
+ numeric, -- actual_hours_worked
+ integer, -- status_id
+ timestamptz, -- creation_date
+ integer, -- creation_user
+ varchar, -- creation_ip
+ integer -- package_id
+) returns integer
+as '
+declare
+ p_task_id alias for $1;
+ p_project_id alias for $2;
+ p_title alias for $3;
+ p_description alias for $4;
+ p_mime_type alias for $5;
+ p_end_date alias for $6;
+ p_percent_complete alias for $7;
+ p_estimated_hours_work alias for $8;
+ p_estimated_hours_work_min alias for $9;
+ p_estimated_hours_work_max alias for $10;
+ p_actual_hours_worked alias for $11;
+ p_status_id alias for $12;
+ p_creation_date alias for $13;
+ p_creation_user alias for $14;
+ p_creation_ip alias for $15;
+ p_package_id alias for $16;
+ v_revision_id cr_revisions.revision_id%TYPE;
+ v_id cr_items.item_id%TYPE;
+begin
+ select acs_object_id_seq.nextval into v_id from dual;
+
+ -- We want to put the task under the project item
+ update cr_items set parent_id = p_project_id where item_id = p_task_id;
+
+ v_revision_id := content_revision__new (
+ p_title, -- title
+ p_description, -- description
+ now(), -- publish_date
+ p_mime_type, -- mime_type
+ NULL, -- nls_language
+ NULL, -- data
+ p_task_id, -- item_id
+ NULL, -- revision_id
+ now(), -- creation_date
+ p_creation_user, -- creation_user
+ p_creation_ip -- creation_ip
+ );
+
+ PERFORM content_item__set_live_revision (v_revision_id);
+
+ insert into pm_tasks_revisions (
+ task_revision_id, end_date, percent_complete, estimated_hours_work, estimated_hours_work_min, estimated_hours_work_max, actual_hours_worked)
+ values (
+ v_revision_id, p_end_date, p_percent_complete, p_estimated_hours_work, p_estimated_hours_work_min, p_estimated_hours_work_max, p_actual_hours_worked);
+
+ update pm_tasks set status = p_status_id where task_id = p_task_id;
+
+ PERFORM acs_permission__grant_permission(
+ v_revision_id,
+ p_creation_user,
+ ''admin''
+ );
+
+ return v_revision_id;
+end;' language 'plpgsql';
Index: openacs-4/packages/project-manager/sql/postgresql/upgrade/upgrade-1.03-1.04b1.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/sql/postgresql/upgrade/upgrade-1.03-1.04b1.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/sql/postgresql/upgrade/upgrade-1.03-1.04b1.sql 29 Apr 2005 17:43:37 -0000 1.1
@@ -0,0 +1,70 @@
+--
+--
+--
+-- @author Jade Rubick (jader@bread.com)
+-- @creation-date 2004-05-19
+-- @arch-tag: 551cfc66-62c5-4f75-a321-e879d75b44b1
+-- @cvs-id $Id: upgrade-1.03-1.04b1.sql,v 1.1 2005/04/29 17:43:37 timoh Exp $
+--
+
+-- fixes name function
+
+create or replace function pm_project__name (integer)
+returns varchar as '
+declare
+ p_pm_project_id alias for $1;
+ v_pm_project_name pm_projectsx.name%TYPE;
+begin
+ select name || ''_'' || p_pm_project_id into v_pm_project_name
+ from pm_projectsx
+ where item_id = p_pm_project_id;
+ return v_pm_project_name;
+end;
+' language 'plpgsql';
+
+
+-- untested fix for bug #1796
+
+create or replace function pm_project__new_root_folder (integer)
+returns integer as '
+declare
+ p_package_id alias for $1;
+
+ v_folder_id cr_folders.folder_id%TYPE;
+ v_folder_name cr_items.name%TYPE;
+begin
+
+ -- raise notice ''in new root folder'';
+
+ -- Set the folder name
+ v_folder_name := pm_project__new_unique_name (p_package_id);
+
+ v_folder_id := content_folder__new (
+ v_folder_name, -- name
+ ''Projects'', -- label
+ ''Project Repository'', -- description
+ p_package_id -- parent_id
+ );
+
+ -- Register the standard content types
+ PERFORM content_folder__register_content_type (
+ v_folder_id, -- folder_id
+ ''pm_project'', -- content_type
+ ''f'' -- include_subtypes
+ );
+
+ -- there is no facility in the API for adding in the package_id,
+ -- so we have to do it ourselves
+
+ update cr_folders
+ set package_id = p_package_id
+ where folder_id = v_folder_id;
+
+ -- TODO: Handle Permissions here for this folder.
+
+ return v_folder_id;
+end;' language 'plpgsql';
+
+-- upgrade script to fix bug #1796
+
+update cr_items set parent_id = (select package_id from cr_folders where folder_id = item_id and label = 'Projects') where item_id = (select folder_id from cr_folders where label = 'Projects' and description = 'Project Repository');
Index: openacs-4/packages/project-manager/sql/postgresql/upgrade/upgrade-1.04b1-1.05.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/sql/postgresql/upgrade/upgrade-1.04b1-1.05.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/sql/postgresql/upgrade/upgrade-1.04b1-1.05.sql 29 Apr 2005 17:43:37 -0000 1.1
@@ -0,0 +1,53 @@
+--
+--
+--
+-- @author Jade Rubick (jader@bread.com)
+-- @creation-date 2004-06-02
+-- @arch-tag: 91272478-d825-42e8-b628-534886dffd84
+-- @cvs-id $Id: upgrade-1.04b1-1.05.sql,v 1.1 2005/04/29 17:43:37 timoh Exp $
+--
+
+create or replace function pm_project__new_root_folder (integer)
+returns integer as '
+declare
+ p_package_id alias for $1;
+
+ v_folder_id cr_folders.folder_id%TYPE;
+ v_folder_name cr_items.name%TYPE;
+begin
+
+ -- raise notice ''in new root folder'';
+
+ -- Set the folder name
+ v_folder_name := pm_project__new_unique_name (p_package_id);
+
+ v_folder_id := content_folder__new (
+ v_folder_name, -- name
+ ''Projects'', -- label
+ ''Project Repository'', -- description
+ null, -- parent_id
+ p_package_id, -- context_id
+ null, -- folder_id
+ null, -- creation_date
+ null, -- creation_user
+ null -- creation_ip
+ );
+
+ -- Register the standard content types
+ PERFORM content_folder__register_content_type (
+ v_folder_id, -- folder_id
+ ''pm_project'', -- content_type
+ ''f'' -- include_subtypes
+ );
+
+ -- there is no facility in the API for adding in the package_id,
+ -- so we have to do it ourselves
+
+ update cr_folders
+ set package_id = p_package_id
+ where folder_id = v_folder_id;
+
+ -- TODO: Handle Permissions here for this folder.
+
+ return v_folder_id;
+end;' language 'plpgsql';
Index: openacs-4/packages/project-manager/sql/postgresql/upgrade/upgrade-1.08b1-1.09b1.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/sql/postgresql/upgrade/upgrade-1.08b1-1.09b1.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/sql/postgresql/upgrade/upgrade-1.08b1-1.09b1.sql 29 Apr 2005 17:43:37 -0000 1.1
@@ -0,0 +1,10 @@
+--
+--
+--
+-- @author Jade Rubick (jader@bread.com)
+-- @creation-date 2004-06-24
+-- @arch-tag: dac85e4c-c80a-4e17-b3ce-6ce34d9510c8
+-- @cvs-id $Id: upgrade-1.08b1-1.09b1.sql,v 1.1 2005/04/29 17:43:37 timoh Exp $
+--
+
+alter table pm_process_task add column ordering integer;
Index: openacs-4/packages/project-manager/sql/postgresql/upgrade/upgrade-2.12-2.13b1.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/sql/postgresql/upgrade/upgrade-2.12-2.13b1.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/sql/postgresql/upgrade/upgrade-2.12-2.13b1.sql 29 Apr 2005 17:43:37 -0000 1.1
@@ -0,0 +1,16 @@
+--
+--
+--
+-- @author Jade Rubick (jader@bread.com)
+-- @creation-date 2004-07-16
+-- @arch-tag: aa453882-e63e-4582-a1d4-097df7792d23
+-- @cvs-id $Id: upgrade-2.12-2.13b1.sql,v 1.1 2005/04/29 17:43:37 timoh Exp $
+--
+
+alter table pm_tasks add column deleted_p char(1);
+
+alter table pm_tasks alter column deleted_p set default 'f';
+update pm_tasks set deleted_p = 'f';
+
+alter table pm_tasks add constraint pm_tasks_deleted_p_ck
+ check (deleted_p in ('t','f'));
Index: openacs-4/packages/project-manager/sql/postgresql/upgrade/upgrade-2.13b1-2.13b2.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/sql/postgresql/upgrade/upgrade-2.13b1-2.13b2.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/sql/postgresql/upgrade/upgrade-2.13b1-2.13b2.sql 29 Apr 2005 17:43:37 -0000 1.1
@@ -0,0 +1,12 @@
+--
+--
+--
+-- @author Jade Rubick (jader@bread.com)
+-- @creation-date 2004-07-16
+-- @arch-tag: 99b969e0-4944-4656-b5f9-61df7e10344c
+-- @cvs-id $Id: upgrade-2.13b1-2.13b2.sql,v 1.1 2005/04/29 17:43:37 timoh Exp $
+--
+
+CREATE OR REPLACE view
+pm_tasks_active as
+ SELECT task_id, task_number, status FROM pm_tasks where deleted_p = 'f';
Index: openacs-4/packages/project-manager/sql/postgresql/upgrade/upgrade-2.15b4-2.16b1.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/sql/postgresql/upgrade/upgrade-2.15b4-2.16b1.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/sql/postgresql/upgrade/upgrade-2.15b4-2.16b1.sql 29 Apr 2005 17:43:37 -0000 1.1
@@ -0,0 +1,22 @@
+--
+--
+--
+-- @author Jade Rubick (jader@bread.com)
+-- @creation-date 2004-09-13
+-- @arch-tag: 858b0c43-d09d-4caa-ad37-09be9b5cbf4d
+-- @cvs-id $Id: upgrade-2.15b4-2.16b1.sql,v 1.1 2005/04/29 17:43:37 timoh Exp $
+--
+
+create table pm_users_viewed (
+ viewing_user integer constraint
+ pm_users_viewed_viewing_user_fk
+ references parties,
+ viewed_user integer constraint
+ pm_users_viewed_viewed_user_fk
+ references parties
+);
+
+comment on table pm_users_viewed is '
+ Used to keep track of what users to see on the task calendar and other
+ views.
+';
Index: openacs-4/packages/project-manager/sql/postgresql/upgrade/upgrade-2.20b3-2.21b1.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/sql/postgresql/upgrade/upgrade-2.20b3-2.21b1.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/sql/postgresql/upgrade/upgrade-2.20b3-2.21b1.sql 29 Apr 2005 17:43:37 -0000 1.1
@@ -0,0 +1,16 @@
+--
+--
+--
+-- @author Jade Rubick (jader@bread.com)
+-- @creation-date 2004-10-08
+-- @arch-tag: fe217011-50b1-4ee9-a686-21dd51cc2384
+-- @cvs-id $Id: upgrade-2.20b3-2.21b1.sql,v 1.1 2005/04/29 17:43:37 timoh Exp $
+--
+
+alter table pm_roles add column is_lead_p char(1)
+ constraint pm_role_is_lead_ck
+ check (is_lead_p in ('t','f'));
+
+alter table pm_roles alter column is_lead_p set default 'f';
+
+update pm_roles set is_lead_p = 't' where one_line = 'Lead';
Index: openacs-4/packages/project-manager/sql/postgresql/upgrade/upgrade-2.21b1-2.50b1.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/sql/postgresql/upgrade/upgrade-2.21b1-2.50b1.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/sql/postgresql/upgrade/upgrade-2.21b1-2.50b1.sql 29 Apr 2005 17:43:37 -0000 1.1
@@ -0,0 +1,165 @@
+--
+--
+--
+-- @author Jade Rubick (jader@bread.com)
+-- @creation-date 2004-10-11
+-- @arch-tag: b03e1fb8-aee1-4429-b6fd-e3e754a5f30a
+-- @cvs-id $Id: upgrade-2.21b1-2.50b1.sql,v 1.1 2005/04/29 17:43:37 timoh Exp $
+--
+
+-- each time a process is used, it creates an instance of that process
+-- we use this to allow a user to see overviews of process status, etc..
+
+create sequence pm_process_instance_seq start 1;
+
+create table pm_process_instance (
+ instance_id integer
+ constraint pm_process_instance_id_pk
+ primary key,
+ name varchar(200),
+ process_id integer
+ constraint pm_process_instance_process_fk
+ references pm_process on delete cascade,
+ project_item_id integer
+ constraint pm_process_project_fk
+ references cr_items
+);
+
+alter table pm_tasks add column
+ process_instance integer
+ constraint pm_tasks_process_instance_fk
+ references pm_process_instance;
+
+drop view pm_tasks_active;
+
+CREATE view
+ pm_tasks_active as
+ SELECT task_id, task_number, status, process_instance FROM pm_tasks where deleted_p = 'f';
+
+
+select define_function_args('pm_task__new_task_item', 'project_id, title, description, html_p, end_date, percent_complete, estimated_hours_work, estimated_hours_work_min, estimated_hours_work_max, status_id, process_instance_id, creation_date, creation_user, creation_ip, package_id');
+
+create or replace function pm_task__new_task_item (
+ integer, -- project_id
+ varchar, -- title
+ varchar, -- description
+ varchar, -- html_p
+ timestamptz, -- end_date
+ numeric, -- percent_complete
+ numeric, -- estimated_hours_work
+ numeric, -- estimated_hours_work_min
+ numeric, -- estimated_hours_work_max,
+ integer, -- status_id
+ integer, -- process_instance_id
+ timestamptz, -- creation_date
+ integer, -- creation_user
+ varchar, -- creation_ip
+ integer -- package_id
+) returns integer
+as '
+declare
+ p_project_id alias for $1;
+ p_title alias for $2;
+ p_description alias for $3;
+ p_mime_type alias for $4;
+ p_end_date alias for $5;
+ p_percent_complete alias for $6;
+ p_estimated_hours_work alias for $7;
+ p_estimated_hours_work_min alias for $8;
+ p_estimated_hours_work_max alias for $9;
+ p_status_id alias for $10;
+ p_process_instance_id alias for $11;
+ p_creation_date alias for $12;
+ p_creation_user alias for $13;
+ p_creation_ip alias for $14;
+ p_package_id alias for $15;
+
+ v_item_id cr_items.item_id%TYPE;
+ v_revision_id cr_revisions.revision_id%TYPE;
+ v_id cr_items.item_id%TYPE;
+ v_task_number integer;
+begin
+ select acs_object_id_seq.nextval into v_id from dual;
+
+ -- We want to put the task under the project item
+
+ -- create the task_number
+
+ v_item_id := content_item__new (
+ v_id::varchar, -- name
+ p_project_id, -- parent_id
+ v_id, -- item_id
+ null, -- locale
+ now(), -- creation_date
+ p_creation_user, -- creation_user
+ p_package_id, -- context_id
+ p_creation_ip, -- creation_ip
+ ''content_item'', -- item_subtype
+ ''pm_task'', -- content_type
+ p_title, -- title
+ p_description, -- description
+ p_mime_type, -- mime_type
+ null, -- nls_language
+ null -- data
+ );
+
+ v_revision_id := content_revision__new (
+ p_title, -- title
+ p_description, -- description
+ now(), -- publish_date
+ p_mime_type, -- mime_type
+ NULL, -- nls_language
+ NULL, -- data
+ v_item_id, -- item_id
+ NULL, -- revision_id
+ now(), -- creation_date
+ p_creation_user, -- creation_user
+ p_creation_ip -- creation_ip
+ );
+
+ PERFORM content_item__set_live_revision (v_revision_id);
+
+ insert into pm_tasks (
+ task_id, task_number, status, process_instance)
+ values (
+ v_item_id, v_task_number, p_status_id, p_process_instance_id);
+
+ insert into pm_tasks_revisions (
+ task_revision_id, end_date, percent_complete, estimated_hours_work, estimated_hours_work_min, estimated_hours_work_max, actual_hours_worked)
+ values (
+ v_revision_id, p_end_date, p_percent_complete, p_estimated_hours_work, p_estimated_hours_work_min, p_estimated_hours_work_max, ''0'');
+
+ PERFORM acs_permission__grant_permission(
+ v_revision_id,
+ p_creation_user,
+ ''admin''
+ );
+
+ return v_revision_id;
+end;' language 'plpgsql';
+
+
+alter table pm_process_task add column
+ mime_type varchar(200)
+ constraint pm_process_task_mime_type_fk
+ references cr_mime_types(mime_type)
+ on update no action on delete no action;
+
+alter table pm_process_task alter column mime_type set default 'text/plain';
+
+update pm_process_task set mime_type = 'text/plain';
+
+alter table pm_process add column
+ deleted_p char(1);
+
+alter table pm_process alter column deleted_p set default 'f';
+
+update pm_process set deleted_p = 'f';
+
+alter table pm_process add constraint pm_process_deleted_p_ck
+ check (deleted_p in ('t','f'));
+
+
+create or replace view
+pm_process_active as
+ SELECT * FROM pm_process where deleted_p = 'f';
Index: openacs-4/packages/project-manager/sql/postgresql/upgrade/upgrade-2.60b1-2.61d1.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/sql/postgresql/upgrade/upgrade-2.60b1-2.61d1.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/sql/postgresql/upgrade/upgrade-2.60b1-2.61d1.sql 29 Apr 2005 17:43:37 -0000 1.1
@@ -0,0 +1,194 @@
+alter table pm_tasks_revisions add column priority integer;
+alter table pm_tasks_revisions alter column priority set default 0;
+update pm_tasks_revisions set priority = 0;
+
+select define_function_args('pm_task__new_task_item', 'project_id, title, description, html_p, end_date, percent_complete, estimated_hours_work, estimated_hours_work_min, estimated_hours_work_max, status_id, process_instance_id, creation_date, creation_user, creation_ip, package_id, priority');
+
+create or replace function pm_task__new_task_item (
+ integer, -- project_id
+ varchar, -- title
+ varchar, -- description
+ varchar, -- html_p
+ timestamptz, -- end_date
+ numeric, -- percent_complete
+ numeric, -- estimated_hours_work
+ numeric, -- estimated_hours_work_min
+ numeric, -- estimated_hours_work_max,
+ integer, -- status_id
+ integer, -- process_instance_id
+ timestamptz, -- creation_date
+ integer, -- creation_user
+ varchar, -- creation_ip
+ integer, -- package_id
+ integer -- priority
+) returns integer
+as '
+declare
+ p_project_id alias for $1;
+ p_title alias for $2;
+ p_description alias for $3;
+ p_mime_type alias for $4;
+ p_end_date alias for $5;
+ p_percent_complete alias for $6;
+ p_estimated_hours_work alias for $7;
+ p_estimated_hours_work_min alias for $8;
+ p_estimated_hours_work_max alias for $9;
+ p_status_id alias for $10;
+ p_process_instance_id alias for $11;
+ p_creation_date alias for $12;
+ p_creation_user alias for $13;
+ p_creation_ip alias for $14;
+ p_package_id alias for $15;
+ p_priority alias for $16;
+
+ v_item_id cr_items.item_id%TYPE;
+ v_revision_id cr_revisions.revision_id%TYPE;
+ v_id cr_items.item_id%TYPE;
+ v_task_number integer;
+begin
+ select acs_object_id_seq.nextval into v_id from dual;
+
+ -- We want to put the task under the project item
+
+ -- create the task_number
+
+ v_item_id := content_item__new (
+ v_id::varchar, -- name
+ p_project_id, -- parent_id
+ v_id, -- item_id
+ null, -- locale
+ now(), -- creation_date
+ p_creation_user, -- creation_user
+ p_package_id, -- context_id
+ p_creation_ip, -- creation_ip
+ ''content_item'', -- item_subtype
+ ''pm_task'', -- content_type
+ p_title, -- title
+ p_description, -- description
+ p_mime_type, -- mime_type
+ null, -- nls_language
+ null -- data
+ );
+
+ v_revision_id := content_revision__new (
+ p_title, -- title
+ p_description, -- description
+ now(), -- publish_date
+ p_mime_type, -- mime_type
+ NULL, -- nls_language
+ NULL, -- data
+ v_item_id, -- item_id
+ NULL, -- revision_id
+ now(), -- creation_date
+ p_creation_user, -- creation_user
+ p_creation_ip -- creation_ip
+ );
+
+ PERFORM content_item__set_live_revision (v_revision_id);
+
+ insert into pm_tasks (
+ task_id, task_number, status, process_instance)
+ values (
+ v_item_id, v_task_number, p_status_id, p_process_instance_id);
+
+ insert into pm_tasks_revisions (
+ task_revision_id, end_date, percent_complete, estimated_hours_work, estimated_hours_work_min, estimated_hours_work_max, actual_hours_worked, priority)
+ values (
+ v_revision_id, p_end_date, p_percent_complete, p_estimated_hours_work, p_estimated_hours_work_min, p_estimated_hours_work_max, ''0'', p_priority);
+
+ PERFORM acs_permission__grant_permission(
+ v_revision_id,
+ p_creation_user,
+ ''admin''
+ );
+
+ return v_revision_id;
+end;' language 'plpgsql';
+
+drop view pm_tasks_revisionsx;
+
+create or replace view pm_tasks_revisionsx as
+ SELECT acs_objects.object_id, acs_objects.object_type, acs_objects.context_id, acs_objects.security_inherit_p, acs_objects.creation_user, acs_objects.creation_date, acs_objects.creation_ip, acs_objects.last_modified, acs_objects.modifying_user, acs_objects.modifying_ip, acs_objects.tree_sortkey, acs_objects.max_child_sortkey, cr.revision_id, cr.title, cr.item_id, cr.description, cr.publish_date, cr.mime_type, cr.nls_language, i.name, i.parent_id, pm_tasks_revisions.task_revision_id, pm_tasks_revisions.end_date, pm_tasks_revisions.percent_complete, pm_tasks_revisions.estimated_hours_work, pm_tasks_revisions.estimated_hours_work_min, pm_tasks_revisions.estimated_hours_work_max, pm_tasks_revisions.actual_hours_worked, pm_tasks_revisions.earliest_start, pm_tasks_revisions.earliest_finish, pm_tasks_revisions.latest_start, pm_tasks_revisions.latest_finish, pm_tasks_revisions.priority
+ FROM acs_objects, cr_revisions cr, cr_items i, cr_text, pm_tasks_revisions
+ WHERE acs_objects.object_id = cr.revision_id AND cr.item_id = i.item_id AND acs_objects.object_id = pm_tasks_revisions.task_revision_id;
+
+
+select define_function_args('pm_task__new_task_revision', 'task_id, project_id, title, description, mime_type, end_date, percent_complete, estimated_hours_work, estimated_hours_work_min, estimated_hours_work_max, actual_hours_worked, creation_date, creation_user, creation_ip, package_id, priority');
+
+create or replace function pm_task__new_task_revision (
+ integer, -- task_id (the item_id)
+ integer, -- project_id
+ varchar, -- title
+ varchar, -- description
+ varchar, -- mime_type
+ timestamptz, -- end_date
+ numeric, -- percent_complete
+ numeric, -- estimated_hours_work
+ numeric, -- estimated_hours_work_min
+ numeric, -- estimated_hours_work_max
+ numeric, -- actual_hours_worked
+ integer, -- status_id
+ timestamptz, -- creation_date
+ integer, -- creation_user
+ varchar, -- creation_ip
+ integer, -- package_id
+ integer -- priority
+) returns integer
+as '
+declare
+ p_task_id alias for $1;
+ p_project_id alias for $2;
+ p_title alias for $3;
+ p_description alias for $4;
+ p_mime_type alias for $5;
+ p_end_date alias for $6;
+ p_percent_complete alias for $7;
+ p_estimated_hours_work alias for $8;
+ p_estimated_hours_work_min alias for $9;
+ p_estimated_hours_work_max alias for $10;
+ p_actual_hours_worked alias for $11;
+ p_status_id alias for $12;
+ p_creation_date alias for $13;
+ p_creation_user alias for $14;
+ p_creation_ip alias for $15;
+ p_package_id alias for $16;
+ p_priority alias for $17;
+ v_revision_id cr_revisions.revision_id%TYPE;
+ v_id cr_items.item_id%TYPE;
+begin
+ select acs_object_id_seq.nextval into v_id from dual;
+
+ -- We want to put the task under the project item
+ update cr_items set parent_id = p_project_id where item_id = p_task_id;
+
+ v_revision_id := content_revision__new (
+ p_title, -- title
+ p_description, -- description
+ now(), -- publish_date
+ p_mime_type, -- mime_type
+ NULL, -- nls_language
+ NULL, -- data
+ p_task_id, -- item_id
+ NULL, -- revision_id
+ now(), -- creation_date
+ p_creation_user, -- creation_user
+ p_creation_ip -- creation_ip
+ );
+
+ PERFORM content_item__set_live_revision (v_revision_id);
+
+ insert into pm_tasks_revisions (
+ task_revision_id, end_date, percent_complete, estimated_hours_work, estimated_hours_work_min, estimated_hours_work_max, actual_hours_worked, priority)
+ values (
+ v_revision_id, p_end_date, p_percent_complete, p_estimated_hours_work, p_estimated_hours_work_min, p_estimated_hours_work_max, p_actual_hours_worked, p_priority);
+
+ update pm_tasks set status = p_status_id where task_id = p_task_id;
+
+ PERFORM acs_permission__grant_permission(
+ v_revision_id,
+ p_creation_user,
+ ''admin''
+ );
+
+ return v_revision_id;
+end;' language 'plpgsql';
Index: openacs-4/packages/project-manager/tcl/calendar-procs-oracle.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/tcl/calendar-procs-oracle.xql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/tcl/calendar-procs-oracle.xql 29 Apr 2005 17:43:37 -0000 1.1
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+ oracle8.0
+
+
+
+ SELECT ts.task_id,
+ ts.task_id as item_id,
+ ts.task_number,
+ t.task_revision_id,
+ t.title,
+ t.parent_id as project_item_id,
+ to_char(t.earliest_start,'J') as earliest_start_j,
+ to_char(sysdate,'J') as today_j,
+ to_char(t.latest_start,'J') as latest_start_j,
+ to_char(t.latest_finish,'J') as latest_finish_j,
+ to_char(t.latest_start,'YYYY-MM-DD HH24:MI') as latest_start,
+ to_char(t.latest_finish,'YYYY-MM-DD HH24:MI') as latest_finish,
+ t.percent_complete,
+ t.estimated_hours_work,
+ t.estimated_hours_work_min,
+ t.estimated_hours_work_max,
+ case when t.actual_hours_worked is null then 0
+ else t.actual_hours_worked end as actual_hours_worked,
+ to_char(t.earliest_start,'YYYY-MM-DD HH24:MI') as earliest_start,
+ to_char(t.earliest_finish,'YYYY-MM-DD HH24:MI') as earliest_finish,
+ to_char(t.latest_start,'YYYY-MM-DD HH24:MI') as latest_start,
+ to_char(t.latest_finish,'YYYY-MM-DD HH24:MI') as latest_finish,
+ p.first_names || ' ' || p.last_name || ' (' ||
+ substr(r.one_line,1,1) || ')' as full_name,
+ p.person_id,
+ s.status_type as status,
+ r.is_lead_p,
+ projectr.title as project_name
+ FROM pm_tasks_active ts,
+ pm_task_status s,
+ cr_items i,
+ pm_tasks_revisionsx t,
+ pm_roles r,
+ persons p,
+ pm_task_assignment ta,
+ cr_items projecti,
+ cr_revisions projectr
+ WHERE ta.role_id = r.role_id (+) and
+ t.item_id = ta.task_id (+) and
+ ta.party_id = p.person_id (+) and
+ ta.role_id = r.role_id and
+ ts.status = s.status_id and
+ ts.task_id = t.item_id and
+ i.item_id = t.item_id and
+ t.task_revision_id = i.live_revision and
+ t.latest_start >= :first_of_month_date and
+ t.latest_start <= :last_of_month_date and
+ t.parent_id = projecti.item_id and
+ projecti.live_revision = projectr.revision_id
+ $hide_closed_clause
+ $selected_users_clause
+ ORDER BY
+ t.latest_start, ts.task_id, r.role_id, p.first_names, p.last_name
+
+
+
+
+
Index: openacs-4/packages/project-manager/tcl/calendar-procs-postgresql.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/tcl/calendar-procs-postgresql.xql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/tcl/calendar-procs-postgresql.xql 29 Apr 2005 17:43:37 -0000 1.1
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+ postgresql7.3
+
+
+
+ SELECT
+ ts.task_id,
+ ts.task_id as item_id,
+ ts.task_number,
+ t.task_revision_id,
+ t.title,
+ t.parent_id as project_item_id,
+ to_char(t.earliest_start,'J') as earliest_start_j,
+ to_char(current_timestamp,'J') as today_j,
+ to_char(t.latest_start,'J') as latest_start_j,
+ to_char(t.latest_finish,'J') as latest_finish_j,
+ to_char(t.latest_start,'YYYY-MM-DD HH24:MI') as latest_start,
+ to_char(t.latest_finish,'YYYY-MM-DD HH24:MI') as latest_finish,
+ t.percent_complete,
+ t.estimated_hours_work,
+ t.estimated_hours_work_min,
+ t.estimated_hours_work_max,
+ case when t.actual_hours_worked is null then 0
+ else t.actual_hours_worked end as actual_hours_worked,
+ to_char(t.earliest_start,'YYYY-MM-DD HH24:MI') as earliest_start,
+ to_char(t.earliest_finish,'YYYY-MM-DD HH24:MI') as earliest_finish,
+ to_char(t.latest_start,'YYYY-MM-DD HH24:MI') as latest_start,
+ to_char(t.latest_finish,'YYYY-MM-DD HH24:MI') as latest_finish,
+ p.first_names || ' ' || p.last_name || ' (' ||
+ substring(r.one_line from 1 for 1) || ')' as full_name,
+ p.person_id,
+ s.status_type as status,
+ r.is_lead_p,
+ projectr.title as project_name
+ FROM
+ pm_tasks_active ts,
+ pm_task_status s,
+ cr_items i,
+ pm_tasks_revisionsx t
+ LEFT JOIN pm_task_assignment ta
+ ON t.item_id = ta.task_id
+ LEFT JOIN persons p
+ ON ta.party_id = p.person_id
+ LEFT JOIN pm_roles r
+ ON ta.role_id = r.role_id,
+ cr_items projecti,
+ cr_revisions projectr
+ WHERE
+ ts.status = s.status_id and
+ ts.task_id = t.item_id and
+ i.item_id = t.item_id and
+ t.task_revision_id = i.live_revision and
+ t.latest_start >= :first_of_month_date and
+ t.latest_start <= :last_of_month_date and
+ t.parent_id = projecti.item_id and
+ projecti.live_revision = projectr.revision_id
+ $hide_closed_clause
+ $selected_users_clause
+ ORDER BY
+ t.latest_start, ts.task_id, r.role_id, p.first_names, p.last_name
+
+
+
+
+
Index: openacs-4/packages/project-manager/tcl/calendar-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/tcl/calendar-procs.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/tcl/calendar-procs.tcl 29 Apr 2005 17:43:37 -0000 1.1
@@ -0,0 +1,164 @@
+#
+
+ad_library {
+
+ Procs to integrate calendar with project-manager
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-08-04
+ @arch-tag: cb98fba5-fba0-449f-9c14-ad9a41bbbd61
+ @cvs-id $Id: calendar-procs.tcl,v 1.1 2005/04/29 17:43:37 timoh Exp $
+}
+
+
+
+namespace eval pm::calendar {
+
+ ad_proc -public users_to_view {
+ } {
+ Returns a list of user_ids for users to view
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-09-13
+
+ @return
+
+ @error
+ } {
+ set user_id [ad_conn user_id]
+
+ set user_list [db_list get_users {
+ SELECT
+ viewed_user
+ FROM
+ pm_users_viewed
+ WHERE
+ viewing_user = :user_id
+ }]
+
+ if {[empty_string_p $user_list]} {
+ return $user_id
+ } else {
+ return $user_list
+ }
+ }
+
+
+ ad_proc -public one_month_display {
+ {-user_id:required}
+ {-date ""}
+ {-hide_closed_p "t"}
+ } {
+ Creates a month widget for tasks
+ } {
+ set day_template "\$day_number"
+ set prev_nav_template "<"
+ set next_nav_template ">"
+
+ if {[empty_string_p $date]} {
+ set date [dt_systime]
+ }
+
+ set date_list [dt_ansi_to_list $date]
+ set month [lindex $date_list 1]
+ set year [lindex $date_list 0]
+
+ set first_of_month_date "$year-$month-01"
+ set last_of_month_date "$year-$month-[dt_num_days_in_month $year $month]"
+
+ set items [ns_set create]
+
+ # do not show closed items if the user requests not to
+ if {[string is true $hide_closed_p]} {
+ set hide_closed_clause " and s.status_type = 'o' "
+ } else {
+ set hide_closed_clause ""
+ }
+
+ set selected_users [pm::calendar::users_to_view]
+ set selected_users_clause " and ts.task_id in (select task_id from pm_task_assignment where party_id in ([join $selected_users ", "]))"
+
+ set last_task_id ""
+ set last_latest_start_j ""
+ set assignee_list [list]
+
+ db_foreach select_monthly_tasks {} {
+
+ # highlight what you're assigned to.
+ if {[string equal $person_id $user_id]} {
+ set font_begin ""
+ set font_end ""
+ } else {
+ set font_begin ""
+ set font_end ""
+ }
+
+ if { \
+ ![empty_string_p $is_lead_p] && \
+ [string is true $is_lead_p]} {
+
+ set font_begin "$font_begin"
+ set font_end "$font_end"
+ }
+
+ # if this is another row of the same item, just add the name.
+ if {[string equal $last_task_id $task_id]} {
+ append day_details "
, ${font_begin}${full_name}${font_end}
"
+ } else {
+
+ # this is the beginning of an item.
+
+ # save the last item for output
+ if {![empty_string_p $last_task_id]} {
+ ns_set put $items $last_latest_start_j "${day_details}"
+ }
+
+ # set up the next item for output
+
+ if {[string equal $status "c"]} {
+ set detail_begin ""
+ set detail_end ""
+ } else {
+ set detail_begin ""
+ set detail_end ""
+ }
+
+ # begin setting up this calendar item
+ set day_details "
+
+ (i-1 means an item that this task depends on)
+
+
+
+ These algorithms are explained at:
+ http://mscmga.ms.ic.ac.uk/jeb/or/netaon.html
+
+ Tasks in ongoing projects are given null completion dates,
+ unless they already have deadlines.
+
+
+
+ The statistics are computed based on:
+
+
+ Project statistics are based on that project + subproject statistics
+
+
+ That means if a project has a subproject, then the tasks for
+ both of those projects are put together in one list, and computed
+ together.
+
+
+
+ So for a project with no subprojects, the values are computed
+ for the tasks in that project
+
+
+ For a project with subprojects, the statistics are based on the
+ tasks of both of those projects.
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-02-19
+
+ @param project_item_id The item_id for the project
+
+ @return a list of task_item_ids of all tasks under a project, plus all subproject tasks. This is done so that the function can be recursive
+
+ @error No error codes
+
+} {
+
+ # Before hacking on this, you might want to look at:
+ # http://www.joelonsoftware.com/articles/fog0000000069.html
+
+ # the first thing that should be done on this code is that it
+ # should be broken out to a number of utility procs.
+
+ set debug 0
+
+ # TODO:
+ #
+ # -------------------------------------------------------------------------
+ # to improve this in the future, be more intelligent about what is updated.
+ # i.e., this procedure updates everything, which is necessary sometimes,
+ # but not if you only edit one task.
+ #
+ # I added in an optimization to only save when something has
+ # changed -- JR
+ # -------------------------------------------------------------------------
+ # Add in resource limits. (it's not realistic that 300 tasks can be done in
+ # one day)
+ # -------------------------------------------------------------------------
+ # Use dependency types -- currently they're all treated like finish_to_start
+ # -------------------------------------------------------------------------
+
+
+ # note if you want to understand the algorithms in this function, you
+ # should look at:
+ # http://mscmga.ms.ic.ac.uk/jeb/or/netaon.html
+
+ if {[string is true $debug]} {
+ ns_log Notice "-----------------------------------------"
+ }
+
+ # --------------------------------------------------------------------
+ # for now, hardcode in a day is 8 hours. Later, we want to set this by
+ # person.
+ # --------------------------------------------------------------------
+ set hours_day [pm::util::hours_day]
+
+
+ # -------------------------
+ # get subprojects and tasks
+ # -------------------------
+ set task_list [list]
+ set task_list_project [list]
+
+ foreach sub_item [db_list_of_lists select_project_children { }] {
+ set my_id [lindex $sub_item 0]
+ set my_type [lindex $sub_item 1]
+
+ if {[string equal $my_type "pm_project"]} {
+
+ # ---------------------------------------------
+ # gets all tasks that are a part of subprojects
+ # ---------------------------------------------
+ set project_return [pm::project::compute_status $my_id]
+ set task_list_project [concat $task_list_project $project_return]
+
+ } elseif {[string equal $my_type "pm_task"]} {
+ lappend task_list $my_id
+ }
+ }
+
+ set task_list [concat $task_list $task_list_project]
+
+ if {[string is true $debug]} {
+ ns_log Notice "Tasks in this project (task_list): $task_list"
+ }
+
+ # -------------------------
+ # no tasks for this project
+ # -------------------------
+ if {[llength $task_list] == 0} {
+ return [list]
+ }
+
+ # --------------------------------------------------------------
+ # we now have list of tasks that includes all subprojects' tasks
+ # --------------------------------------------------------------
+
+ # returns actual_hours_completed, estimated_hours_total, and
+ # today_j (julian date for today)
+ db_1row tasks_group_query { }
+
+ if {[string is true $debug]} {
+ ns_log notice "Today's date (julian format): $today_j"
+ }
+
+ # --------------------------------------------------------------
+ # Set up activity_time for all tasks
+ # Also set up deadlines for tasks that have hard-coded deadlines
+ # --------------------------------------------------------------
+
+ if {[string is true $debug]} {
+ ns_log notice "Going through tasks and saving their values"
+ }
+
+ db_foreach tasks_query { } {
+
+ # We now save information about all the tasks, so that we can
+ # save on database hits later. Specifically, what we'll do is
+ # we won't need to save changes if the earliest_start,
+ # earliest finish, latest_start and latest_finish all haven't
+ # changed at all. We also save whether the task is open (o) or
+ # closed(c).
+
+ set old_ES_j($my_iid) $old_earliest_start_j
+ set old_EF_j($my_iid) $old_earliest_finish_j
+ set old_LS_j($my_iid) $old_latest_start_j
+ set old_LF_j($my_iid) $old_latest_finish_j
+ set task_percent_complete($my_iid) $my_percent_complete
+
+ set activity_time($my_iid) [expr [expr $to_work * [expr 100 - $my_percent_complete] / 100]]
+
+ if {[exists_and_not_null task_deadline_j]} {
+
+ if {[string is true $debug]} {
+ ns_log notice "$my_iid has a deadline (julian: $task_deadline_j)"
+ }
+
+ set latest_finish($my_iid) $task_deadline_j
+
+ set latest_start($my_iid) [pm::project::latest_start \
+ -end_date_j $task_deadline_j \
+ -hours_to_complete $activity_time($my_iid) \
+ -hours_day $hours_day]
+
+ }
+ }
+
+ # --------------------------------------------------------------------
+ # We need to keep track of all the dependencies so we can meaningfully
+ # compute deadlines, earliest start times, etc..
+ # --------------------------------------------------------------------
+
+ db_foreach dependency_query { } {
+
+ # task_item_id depends on parent_task_id
+ lappend depends($task_item_id) $parent_task_id
+
+ # parent_task_id is dependent on task_item_id
+ lappend dependent($parent_task_id) $task_item_id
+
+ set dependency_types($task_item_id-$parent_task_id) $dependency_type
+
+ if {[string is true $debug]} {
+ ns_log Notice "dependency (id: $dependency_id) task: $task_item_id parent: $parent_task_id type: $dependency_type"
+ }
+ }
+
+
+ # --------------------------------------------------------------
+ # need to get some info on this project, so that we can base the
+ # task information off of them
+ # --------------------------------------------------------------
+
+ # gives up end_date_j, start_date_j, and ongoing_p
+ # if ongoing_p is t, then end_date_j should be null
+ db_1row project_info { }
+
+ if {[string is true $ongoing_p] && ![empty_string_p $end_date_j]} {
+ ns_log Error "Project cannot be ongoing and have a non-null end-date. Setting end date to blank"
+ set end_date_j ""
+ }
+
+
+ # --------------------------------------------------------------
+ # task_list contains all the tasks
+ # a subset of those do not depend on any other tasks
+ # --------------------------------------------------------------
+
+ # ----------------------------------------------------------------------
+ # we want to go through and fill in all the values for earliest start.
+ # the brain-dead, brute force way of doing this, would be go through the
+ # task_list length(task_list) times, and each time, compute the values
+ # for each item that depends on one of those tasks. This is extremely
+ # inefficient.
+ # ----------------------------------------------------------------------
+ # Instead, we create two lists, one is of tasks we just added
+ # earliest_start values for, the next is a new list of ones we're going to
+ # add earliest_start values for. We call these lists
+ # present_tasks and future_tasks
+ # ----------------------------------------------------------------------
+
+ set present_tasks [list]
+ set future_tasks [list]
+
+ # -----------------------------------------------------
+ # make a list of tasks that don't depend on other tasks
+ # -----------------------------------------------------
+ # while we're at it, save earliest_start and earliest_finish
+ # info for these items
+ # -----------------------------------------------------
+
+ foreach task_item $task_list {
+
+ if {![info exists depends($task_item)]} {
+
+ set earliest_start($task_item) $start_date_j
+ set earliest_finish($task_item) [earliest_finish $earliest_start($task_item) $activity_time($task_item) $hours_day]
+
+ lappend present_tasks $task_item
+
+ if {[string is true $debug]} {
+ ns_log Notice "preliminary earliest_start($task_item): $earliest_start($task_item)"
+ }
+ }
+ }
+
+ # -------------------------------
+ # stop if we have no dependencies
+ # -------------------------------
+ if {[llength $present_tasks] == 0} {
+
+ if {[string is true $debug]} {
+ ns_log Notice "No tasks with dependencies"
+ }
+
+ return [list]
+ }
+
+ if {[string is true $debug]} {
+ ns_log Notice "present_tasks: $present_tasks"
+ }
+
+ # ------------------------------------------------------
+ # figure out the earliest start and finish times
+ # ------------------------------------------------------
+
+ while {[llength $present_tasks] > 0} {
+
+ set future_tasks [list]
+
+ foreach task_item $present_tasks {
+
+ if {[string is true $debug]} {
+ ns_log Notice "-this task_item: $task_item"
+ }
+
+ # -----------------------------------------------------
+ # some tasks may already have earliest_start filled in
+ # the first run of tasks, for example, had their values
+ # filled in earlier
+ # -----------------------------------------------------
+
+ if {![exists_and_not_null earliest_start($task_item)]} {
+
+ if {[string is true $debug]} {
+ ns_log Notice " !info exists for $task_item"
+ }
+
+ # ---------------------------------------------
+ # set the earliest_start for this task =
+ # max(activity_time(i-1) + earliest_start(i-1))
+ #
+ # (i-1 means an item that this task depends on)
+ # ---------------------------------------------
+
+ set max_earliest_start 0
+
+ # testing if this fixes the bug
+ if {![exists_and_not_null depends($task_item)]} {
+ set depends($task_item) [list]
+ }
+
+ foreach dependent_item $depends($task_item) {
+
+ set my_earliest_start [my_earliest_start $earliest_start($dependent_item) $activity_time($dependent_item) $hours_day]
+
+ if {$my_earliest_start > $max_earliest_start} {
+ set max_earliest_start $my_earliest_start
+ }
+ }
+
+ set earliest_start($task_item) $max_earliest_start
+
+ set earliest_finish($task_item) [earliest_finish $max_earliest_start $activity_time($task_item) $hours_day]
+
+ if {[string is true $debug]} {
+ ns_log Notice \
+ " earliest_start ($task_item): $earliest_start($task_item)"
+ ns_log Notice \
+ " earliest_finish($task_item): $earliest_finish($task_item)"
+ }
+
+ }
+
+ # -------------------------------
+ # add to list of tasks to process
+ # -------------------------------
+
+ if {[info exists dependent($task_item)]} {
+ set future_tasks [concat $future_tasks $dependent($task_item)]
+ }
+ }
+
+ if {[string is true $debug]} {
+ ns_log Notice "future tasks: $future_tasks"
+ }
+
+ set present_tasks $future_tasks
+ }
+
+ # ----------------------------------------------
+ # set up earliest date project will be completed
+ # ----------------------------------------------
+
+ set max_earliest_finish $today_j
+
+ foreach task_item $task_list {
+
+ if {[string is true $debug] && [exists_and_not_null earliest_finish($task_item)]} {
+ ns_log Notice "* EF: ($task_item): $earliest_finish($task_item)"
+ }
+
+ if {[exists_and_not_null earliest_finish($task_item)] && $max_earliest_finish < $earliest_finish($task_item)} {
+ set max_earliest_finish $earliest_finish($task_item)
+ }
+
+ }
+
+
+ # -----------------------------------------------------------------
+ # Now compute latest_start and latest_finish dates.
+ # Note the latest_finish dates may be set to an arbitrary deadline.
+ # Also note that it is possible for a project to be ongoing.
+ # In that case, the latest_start and latest_finish dates should
+ # be set to null, unless there is a hard deadline (end_date).
+ # -----------------------------------------------------------------
+ # If these represent the dependency hierarchy:
+ # 2155
+ # / | \
+ # 2161 2173 2179
+ # | |
+ # 2167 2195
+ # ----------------------------------------------------------------------
+ # we want to go through and fill in all the values for latest start
+ # and latest_finish.
+ # the brain-dead, brute force way of doing this, would be go through the
+ # task_list length(task_list) times, and each time, compute the values
+ # for each item that depends on one of those tasks. This is extremely
+ # inefficient.
+ # ----------------------------------------------------------------------
+ # Instead, we create two lists, one is of tasks we just added
+ # latest_finish values for, the next is a new list of ones we're going to
+ # add latest_finish values for. We call these lists
+ # present_tasks and future_tasks
+ # ----------------------------------------------------------------------
+ # Here's a description of the algorithm.
+ # 1. The algorithm starts with those tasks that don't have other
+ # tasks depending on them.
+ #
+ # So in the example above, we'll start with
+ # present_tasks: 2167 2173 2195
+ # future tasks:
+ #
+ # 2. While we make the present_tasks list, we store latest_start
+ # and latest_finish information for each of those tasks. If the
+ # project is ongoing, then we also keep track of tasks that have
+ # no latest_start or latest_finish. We keep this in the
+ # ongoing_task(task_id) array. If is exists, then we know that
+ # that task is an ongoing task, so no deadline will exist for it.
+ #
+ # 3. Stop if we don't have any dependencies
+ #
+ # 4. Then we get into a loop.
+ # While there are present_tasks:
+ # Create the future_tasks list
+ # For each present task:
+ # If the task has a dependent task:
+ # Go through these dependent tasks:
+ # If the dependent task is ongoing don't defer
+ # If the dependent task doesn't have LS set,
+ # then defer, and add to future_tasks list
+ # Otherwise set the LS value for that task
+ # If there are no deferals, get the minimum LS of
+ # dependents, set LF
+ # Add the dependent tasks to the future_tasks
+ # Set present_tasks equal to future_tasks, clear future_tasks
+
+ # ----------------------------------------------------------------------
+ # The biggest problem with this algorithm is that you can have items at
+ # two different levels in the hierarchy.
+ #
+ # if you trace through this algorithm, you'll see that we'll get to 2155
+ # before 2161's values have been set, which can cause an error. The
+ # solution we arrive at is to defer to the future_tasks list any item
+ # that causes an error. That should work.
+
+ set present_tasks [list]
+ set future_tasks [list]
+
+ # -----------------------------------------------------
+ # make a list of tasks that don't have tasks depend on them
+ # -----------------------------------------------------
+ # while we're at it, save latest_start and latest_finish
+ # info for these items
+ # -----------------------------------------------------
+
+ if {[string is true $debug]} {
+ ns_log Notice "Starting foreach task-item $task_list"
+ }
+
+ foreach task_item $task_list {
+
+ if {![info exists dependent($task_item)]} {
+
+ if {[string is true $debug]} {
+ ns_log Notice " !info exists dependent($task_item)"
+ }
+
+ # we check this because some tasks already have
+ # hard deadlines set.
+ if {[info exists latest_finish($task_item)]} {
+
+ # if the project needs to be completed before the
+ # actual hard deadline, then the project deadline
+ # has precedence. However, sometimes the project is
+ # ongoing, so we have to make sure that there actually
+ # is an end_date_j
+
+ # commented out: we need to trust the user. If they
+ # set the deadline outside the project deadline,
+ # that's their business
+
+ #if {![empty_string_p $end_date_j]} {
+ # if {$end_date_j < $latest_finish($task_item)} {
+ # set latest_finish($task_item) $end_date_j
+ # }
+ #}
+
+ # we also set the latest_start date
+
+ if {[string is false [exists_and_not_null activity_time($task_item)]]} {
+ set activity_time($task_item) 0
+ ns_log Notice "setting activity_time($task_item) 0"
+ }
+
+ set late_start_temp \
+ [latest_start \
+ -end_date_j $latest_finish($task_item) \
+ -hours_to_complete $activity_time($task_item) \
+ -hours_day $hours_day]
+
+ if {$late_start_temp < $latest_start($task_item)} {
+ set latest_start($task_item) $late_start_temp
+ }
+
+ } else {
+
+ # this section is for items that have no solid
+ # deadline, but also have no items dependent on them
+
+ # we either set the latest start and finish of the item or
+ # we specify that the task is an ongoing task
+ if {[empty_string_p $end_date_j]} {
+ set ongoing_task($task_item) true
+
+ if {[string is true $debug]} {
+ ns_log Notice "NSDBAHNITD: end_date_j was empty ti:$task_item"
+ }
+ } else {
+ set latest_finish($task_item) $end_date_j
+
+ if {[string is false [exists_and_not_null activity_time($task_item)]]} {
+ set activity_time($task_item) 0
+ ns_log Notice "setting activity_time($task_item) 0 (location 2)"
+ }
+
+ set latest_start($task_item) \
+ [latest_start \
+ -end_date_j $latest_finish($task_item) \
+ -hours_to_complete $activity_time($task_item) \
+ -hours_day $hours_day]
+
+ }
+ }
+ lappend present_tasks $task_item
+
+ if {[string is true $debug] && [exists_and_not_null latest_start($task_item)]} {
+ ns_log Notice "preliminary latest_start($task_item): $latest_start($task_item)"
+ }
+
+ if {[string is true $debug] && [exists_and_not_null latest_finish($task_item)]} {
+ ns_log Notice "preliminary latest_finish($task_item): $latest_finish($task_item)"
+ }
+
+
+
+ } else {
+ if {[string is true $debug]} {
+ ns_log Notice " info exists dependent($task_item)"
+ }
+ }
+ }
+
+
+ # -------------------------------
+ # stop if we have no dependencies
+ # -------------------------------
+ if {[llength $present_tasks] == 0} {
+ if {[string is true $debug]} {
+ ns_log Notice "No tasks with dependencies"
+ }
+ return [list]
+ }
+
+ if {[string is true $debug]} {
+ ns_log Notice "LATEST present_tasks: $present_tasks"
+ }
+
+ # ------------------------------------------------------
+ # figure out the latest start and finish times
+ # ------------------------------------------------------
+
+ while {[llength $present_tasks] > 0} {
+
+ set future_tasks [list]
+
+ foreach task_item $present_tasks {
+
+ if {[string is true $debug]} {
+ ns_log Notice "this task_item: $task_item"
+ }
+
+ # -----------------------------------------------------
+ # some tasks may already have latest_start filled in.
+ # the first run of tasks, for example, had their values
+ # filled in earlier
+ # -----------------------------------------------------
+
+ if {[info exists dependent($task_item)]} {
+
+ if {[string is true $debug]} {
+ ns_log Notice " info exists for dependent($task_item)"
+ }
+
+ # ---------------------------------------------
+ # set the latest_start for this task =
+ # min(latest_start(i+1) - activity_time(i))
+ #
+ # (i+1 means an item that depends on this task)
+ # (i means this task)
+ # ---------------------------------------------
+
+ # we set this to the end date, and then move it forward
+ # as we find dependent items that have earlier
+ # latest_start dates. The problem is that the
+ # end_date_j is empty when there is no deadline.
+ # So we need to remember that min_latest_start can
+ # be an empty value
+
+ set min_latest_start $end_date_j
+
+ if {[string is true $debug]} {
+ ns_log Notice " min_latest_start: $end_date_j"
+ }
+
+ foreach dependent_item $dependent($task_item) {
+
+ if {[string is true $debug]} {
+ ns_log Notice " dependent_item: $dependent_item"
+ }
+
+ if {[exists_and_not_null ongoing_task($dependent_item)]} {
+ set defer_p f
+ set my_latest_start ""
+
+ if {[string is true $debug]} {
+ ns_log Notice " ongoing_task, no defer"
+ }
+
+ } elseif {![exists_and_not_null latest_start($dependent_item)]} {
+ # we defer the task if the dependent item has no
+ # latest_start date set
+
+ if {[info exists defer_count($task_item)]} {
+ incr defer_count($task_item)
+ } else {
+ set defer_count($task_item) 1
+ }
+
+ # we use a magic number here.
+ # basically, we don't want to defer the
+ # item forever. Ideally, this should
+ # be cleaned up better. Defering is necessary
+ # given this algorithm, but there are
+ # times when you don't want to defer.
+ # This is hackish, and I'm embarrased, but on
+ # a deadline. :(
+ if {$defer_count($task_item) > 5} {
+ set defer_p f
+
+ if {[string is true $debug]} {
+ ns_log Notice " no defer because defer count exceeded"
+ }
+ } else {
+ lappend future_tasks $task_item
+
+ if {[string is true $debug]} {
+ ns_log Notice " defer"
+ }
+
+ set defer_p t
+ }
+
+
+
+ } else {
+
+ # the dependent item has a deadline
+
+ if {[string is false [exists_and_not_null activity_time($task_item)]]} {
+ set activity_time($task_item) 0
+ ns_log Notice "setting activity_time($task_item) 0 (location 3)"
+ }
+
+ set my_latest_start \
+ [latest_start \
+ -end_date_j $latest_start($dependent_item) \
+ -hours_to_complete $activity_time($task_item) \
+ -hours_day $hours_day]
+
+ if {[string is true $debug]} {
+ ns_log Notice " my_latest_start: $my_latest_start"
+ }
+
+ # we also only want to move forward the latest_start
+ # date if the dependent item is not already completed!
+
+ if {$task_percent_complete($dependent_item) < 100} {
+ if {[exists_and_not_null min_latest_start]} {
+ if {$my_latest_start < $min_latest_start} {
+ set min_latest_start $my_latest_start
+ }
+ } else {
+ set min_latest_start $my_latest_start
+ }
+ }
+
+ set defer_p f
+ }
+
+ }
+
+ if {[string equal $defer_p f]} {
+
+ # we check that latest_start doesn't already exist
+ # which it might for hard-deadlines
+
+ # we have to be fairly careful here. We want to
+ # set the latest_start date to the minimum
+ # latest_start, but only when min_latest_start
+ # actually has a value
+
+ if {[exists_and_not_null latest_start($task_item)]} {
+
+ if {[exists_and_not_null min_latest_start]} {
+
+ if {$min_latest_start < $latest_start($task_item)} {
+ set latest_start($task_item) $min_latest_start
+ }
+
+ } else {
+
+ if {[string is true $debug]} {
+ ns_log notice " setting latest start date (ignoring min_latest_start"
+ }
+
+ if {[string is false [exists_and_not_null activity_time($task_item)]]} {
+ set activity_time($task_item) 0
+ ns_log Notice "setting activity_time($task_item) 0 (location 4)"
+ }
+
+
+ set latest_start($task_item) \
+ [latest_start \
+ -end_date_j $latest_finish($task_item) \
+ -hours_to_complete $activity_time($task_item) \
+ -hours_day $hours_day]
+
+ }
+ } else {
+
+ # so this task has no hard deadline.
+ # We now set the value to the minimum of the
+ # dependent tasks. Note that if the dependent
+ # tasks all have no hard deadlines, and the
+ # project is ongoing, then the value will be
+ # set to ""
+
+ set latest_start($task_item) $min_latest_start
+ }
+
+ if {[string is true $debug]} {
+ ns_log Notice " min_latest_start: $min_latest_start"
+ }
+
+ # we now set the latest finish. Ongoing tasks set
+ # the latest finish to empty (sometimes)
+ if {[empty_string_p $latest_start($task_item)]} {
+ set temp_lf ""
+ } else {
+ set temp_lf [my_latest_finish $min_latest_start $activity_time($task_item) $hours_day]
+ }
+
+ # if there is already a hard deadline for this
+ # task, then we check whether temp_lf is earlier,
+ # and set it to temp_lf if so
+
+ if {[string is true $debug]} {
+ ns_log Notice " temp_lf: $temp_lf"
+ }
+
+ if {[empty_string_p $temp_lf]} {
+
+ # if the task is ongoing, we clear the
+ # latest_finish. Otherwise, we leave the
+ # latest_finish as it is.
+
+ if {[exists_and_not_null ongoing_task($task_item)] && [string is true $ongoing_task($task_item)]} {
+ set latest_finish($task_item) ""
+ }
+
+ } else {
+ if {[exists_and_not_null latest_finish($task_item)]} {
+ if {$temp_lf < $latest_finish($task_item)} {
+ set latest_finish($task_item) $temp_lf
+ }
+ } else {
+ set latest_finish($task_item) $temp_lf
+ }
+ }
+
+ if {[string is true $debug]} {
+ if {[exists_and_not_null latest_start($task_item)]} {
+ ns_log Notice \
+ " latest_start ($task_item): $latest_start($task_item)"
+ }
+ if {[exists_and_not_null latest_finish($task_item)]} {
+ ns_log Notice \
+ " latest_finish($task_item): $latest_finish($task_item)"
+ }
+ }
+
+ } else {
+ if {[string is true $debug]} {
+ ns_log Notice "Deferring $task_item"
+ }
+ }
+ }
+
+ # -------------------------------
+ # add to list of tasks to process
+ # -------------------------------
+
+ if {[info exists depends($task_item)]} {
+ set future_tasks [concat $future_tasks $depends($task_item)]
+ }
+ }
+
+ if {[string is true $debug]} {
+ ns_log Notice "future tasks: $future_tasks"
+ }
+
+ set present_tasks $future_tasks
+ }
+
+ # ----------------------------------------------
+ # set up latest start date for project
+ # ----------------------------------------------
+
+ if {[empty_string_p $end_date_j]} {
+ set min_latest_start ""
+ set max_earliest_finish ""
+ } else {
+ set min_latest_start $end_date_j
+
+ foreach task_item $task_list {
+
+ if {[string is true $debug]} {
+ ns_log Notice "* LS ($task_item): $latest_start($task_item)"
+ }
+
+ if {[exists_and_not_null earliest_finish($task_item)] && $min_latest_start > $latest_start($task_item)} {
+ set max_earliest_finish $earliest_finish($task_item)
+ }
+ }
+
+ set max_earliest_finish "J[expr floor([set max_earliest_finish])]"
+ set min_latest_start "J[expr floor([set min_latest_start])]"
+ }
+
+
+ # estimated_finish_date
+ # latest_finish
+
+ db_dml update_project { }
+
+ # now we go through and save all the values for the tasks!
+ # this is very inefficient and stupid
+
+ foreach task_item $task_list {
+
+ if {[exists_and_not_null earliest_start($task_item)]} {
+ set es "J[expr ceil( [set earliest_start($task_item)])]"
+ } else {
+ set es ""
+ }
+
+ if {[exists_and_not_null earliest_finish($task_item)]} {
+ set ef "J[expr ceil( [set earliest_finish($task_item)])]"
+ } else {
+ set ef ""
+ }
+
+ if {[exists_and_not_null latest_start($task_item)]} {
+ set ls "J[expr floor([set latest_start($task_item)])]"
+ } else {
+ set ls ""
+ }
+
+ if {[exists_and_not_null latest_finish($task_item)]} {
+ set lf "J[expr floor($latest_finish($task_item))]"
+ } else {
+ set lf ""
+ }
+
+ # Only update the task if something has actually
+ # changed. Hopefully this should help speed things up.
+
+ if { \
+ [string equal $es $old_ES_j($task_item)] && \
+ [string equal $ef $old_EF_j($task_item)] && \
+ [string equal $ls $old_LS_j($task_item)] && \
+ [string equal $lf $old_LF_j($task_item)]} {
+ # do nothing
+ } else {
+ db_dml update_task { }
+ }
+
+
+ }
+
+
+ if {[string is true $debug]} {
+ ns_log Notice "*******************"
+ }
+
+ return $task_list
+
+}
+
+
+
+
+ad_proc -public pm::project::compute_parent_status {project_item_id} {
+
+ When a project is updated, or a task updated within a project, we need to
+ update all the projects higher in the hierarchy.
+
+ This may need to be fixed to add back in subproject support.
+} {
+ set package_id [pm::util::package_id]
+
+ # ns_log Notice "computing parents for $project_item_id and package_id: $package_id"
+
+
+ set my_item_id $project_item_id
+ set parent_id [db_string get_parent_id {}]
+ set last_item_id $my_item_id
+
+ # trace up the hierarchy until we get one below the root
+
+ set root_folder [db_exec_plsql get_root_folder { }]
+
+ while {$parent_id != $root_folder && $parent_id != "-1"} {
+ set parent_id [db_string get_parent_id {} -default "-1"]
+ set last_item_id $my_item_id
+ set my_item_id $parent_id
+ }
+
+ # ns_log Notice "root: $root_folder , last_item_id $last_item_id"
+
+ set return_code [pm::project::compute_status $last_item_id]
+
+ return $return_code
+}
+
+
+
+ad_proc -public pm::project::get_logger_project {
+ -project_item_id:required
+} {
+ Returns logger's project ID when given project manager's project ID
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-03-04
+
+ @param project_item_id
+
+ @return logger's project_id
+
+ @error returns no_project if no such project_item_id exists
+} {
+ return [db_string get_logger_project "
+ SELECT
+ logger_project
+ FROM
+ pm_projects
+ WHERE
+ project_id =
+ (select live_revision from cr_items where item_id = :project_item_id)
+ " -default "no_project"]
+}
+
+
+ad_proc -public pm::project::get_project {
+ -logger_project:required
+} {
+ Returns the project_item_id when given the logger project
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-05-28
+
+ @param logger_project
+
+ @return project_item_id
+
+ @error
+} {
+ return [db_string get_logger_project "
+ SELECT
+ i.item_id
+ FROM
+ pm_projectsx p, cr_items i
+ WHERE
+ i.live_revision = p.revision_id and logger_project = :logger_project
+ " -default "no_project"]
+
+}
+
+
+ad_proc -public pm::project::get_list_of_open {
+} {
+ Returns a list of lists, of all open project ids and their names.
+
+ We should util_memoize this. It will dramatically improve the
+ speed of the task edits.
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-05-13
+
+ @return list of lists, with project id and name
+
+ @error
+} {
+
+ set return_val [db_list_of_lists get_vals { }]
+
+ return $return_val
+}
+
+
+ad_proc -public pm::project::select_list_of_open {
+ {-selected ""}
+} {
+ Returns a select list of all open project ids and their names
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-10-13
+
+ @return html for select list of open projects
+
+ @error
+} {
+ # is the selected project closed?
+ set open_p [pm::project::open_p -project_item_id $selected]
+
+ if {[string is false $open_p]} {
+ set name [pm::project::name -project_item_id $selected]
+ set html ""
+ } else {
+ set html ""
+ }
+
+ set list_of_lists [pm::project::get_list_of_open]
+
+ foreach lol $list_of_lists {
+ set name [lindex $lol 0]
+ set id [lindex $lol 1]
+
+ if {[string equal $id $selected]} {
+ set sel "selected=\"selected\""
+ } else {
+ set sel ""
+ }
+
+ append html "\n"
+ }
+
+ return $html
+}
+
+
+ad_proc -public pm::project::close {
+ {-project_item_id:required}
+} {
+ Closes a project
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-07-02
+
+ @param project_item_id
+
+ @return
+
+ @error
+} {
+
+ set closed_id [pm::status::default_closed]
+
+ db_dml update_status {
+ UPDATE
+ pm_projects
+ SET
+ status_id = :closed_id
+ WHERE
+ project_id in (select live_revision from cr_items where item_id = :project_item_id)
+ }
+
+}
+
+
+ad_proc -public pm::project::open_p {
+ {-project_item_id:required}
+} {
+ Returns true if the project is open
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-06-03
+
+ @param project_item_id
+
+ @return 1 if open, 0 if closed
+
+ @error
+} {
+ set return_val [db_string get_open_or_closed {
+ SELECT
+ case when status_type = 'c' then 0 else 1 end
+ FROM
+ pm_projectsx p,
+ cr_items i,
+ pm_project_status s
+ WHERE
+ i.item_id = p.item_id and
+ i.live_revision = p.revision_id and
+ p.status_id = s.status_id and
+ p.item_id = :project_item_id
+ } -default "0"]
+
+ return $return_val
+}
+
+
+ad_proc -public pm::project::assign {
+ {-project_item_id:required}
+ {-role_id:required}
+ {-party_id:required}
+ {-send_email_p "t"}
+} {
+ Assigns a user to a project
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-06-11
+
+ @param project_item_id
+
+ @param role_id
+
+ @param party_id
+
+ @return
+
+ @error
+} {
+
+ db_dml insert_assignment {
+ insert into pm_project_assignment
+ (project_id, role_id, party_id)
+ VALUES
+ (:project_item_id, :role_id, :party_id)
+ }
+
+ # Flush the cache that remembers which roles to offer the current user in the 'assign role to myself' listbox
+ util_memoize_flush [list pm::role::project_select_list_filter_not_cached -project_item_id $project_item_id -party_id $party_id]
+
+ if {[string is true $send_email_p]} {
+
+ set project_name [pm::project::name \
+ -project_item_id $project_item_id]
+
+ set project_url [pm::project::url \
+ -project_item_id $project_item_id]
+
+ set to_addr [cc_email_from_party $party_id]
+ set from_addr [cc_email_from_party [ad_conn user_id]]
+ set role [pm::role::name -role_id $role_id]
+
+ set subject "Assigned to project: $project_name"
+
+ set content "
You have been assigned to a project: $project_name (as $role)
"
+
+
+ pm::util::email \
+ -to_addr $to_addr \
+ -from_addr $from_addr \
+ -subject $subject \
+ -body $content \
+ -mime_type "text/html"
+ }
+
+ return
+}
+
+
+ad_proc -public pm::project::unassign {
+ {-project_item_id:required}
+ {-party_id:required}
+} {
+ Removes a user from a project
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-06-11
+
+ @param project_item_id
+
+ @param party_id
+
+ @return
+
+ @error
+} {
+
+ db_dml remove_assignment {
+ DELETE FROM
+ pm_project_assignment
+ WHERE
+ project_id = :project_item_id and
+ party_id = :party_id
+ }
+
+ # Flush the cache that remembers which roles to offer the current user in the 'assign role to myself' listbox
+ if {[ad_conn user_id == $party_id]} {
+ util_memoize_flush [list pm::role::project_select_list_filter_not_cached -project_item_id $project_item_id -party_id $party_id]
+ }
+
+ return
+}
+
+
+ad_proc -public pm::project::assign_remove_everyone {
+ {-project_item_id:required}
+} {
+ Removes all users from a project
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-06-11
+
+ @param project_item_id
+
+ @return party_ids of all users removed from the project
+
+ @error
+} {
+
+ set current_assignees [db_list get_assignees {
+ SELECT
+ party_id
+ FROM
+ pm_project_assignment
+ WHERE
+ project_id = :project_item_id
+ }]
+
+ db_dml remove_assignment {
+ DELETE FROM
+ pm_project_assignment
+ WHERE
+ project_id = :project_item_id
+ }
+
+ # Flush the cache that remembers which roles to offer the current user in the 'assign role to myself' listbox
+ util_memoize_flush [list pm::role::project_select_list_filter_not_cached -project_item_id $project_item_id -party_id [ad_conn user_id]]
+ return $current_assignees
+}
+
+
+ad_proc -public pm::project::assignee_filter_select {
+ {-status_id:required}
+} {
+ Returns a list of lists, people who are assigned to projects with a
+ status of status_id. Used in the list-builder filters for
+ the projects list page. Cached 5 minutes.
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-06-11
+
+ @param status_id
+
+ @return
+
+ @error
+} {
+ return [util_memoize [list pm::project::assignee_filter_select_helper -status_id $status_id] 600]
+}
+
+
+ad_proc -private pm::project::assignee_filter_select_helper {
+ {-status_id:required}
+} {
+ Returns a list of lists, people who are assigned projects with a
+ status of status_id. Used in the list-builder filters for
+ the projects list page. Cached 5 minutes.
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-06-11
+
+ @param status_id
+
+ @return
+
+ @error
+} {
+ return [db_list_of_lists get_people {
+SELECT
+ distinct(first_names || ' ' || last_name) as fullname,
+ u.person_id
+ FROM
+ persons u,
+ pm_project_assignment a,
+ pm_projects p,
+ cr_items i
+ WHERE
+ u.person_id = a.party_id and
+ i.item_id = a.project_id and
+ p.status_id = :status_id and
+ i.live_revision = p.project_id
+ ORDER BY
+ fullname
+ }]
+}
+
+
+ad_proc -public pm::project::assignee_email_list {
+ -project_item_id:required
+} {
+ Returns a list of assignee email addresses
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-06-30
+
+ @param project_item_id
+
+ @return
+
+ @error
+} {
+
+ return [db_list get_addresses {
+ SELECT
+ p.email
+ FROM
+ parties p,
+ pm_project_assignment a
+ WHERE
+ a.project_id = :project_item_id and
+ a.party_id = p.party_id
+ }]
+
+}
+
+
+ad_proc -public pm::project::assigned_p {
+ -project_item_id:required
+ -party_id:required
+} {
+ Returns 1 if user has been assigned to a project
+
+ @author Richard Hamilton (ricky.hamilton@btopenworld.com)
+ @creation-date 2004-12-17
+
+ @param project_item_id
+
+ @param party_id
+
+ @return
+
+ @error
+} {
+
+ return [db_0or1row assigned_p {
+ SELECT
+ party_id
+ FROM
+ pm_project_assignment
+ WHERE
+ project_id = :project_item_id and
+ party_id = :party_id
+ LIMIT 1
+ }]
+
+}
+
+
+ad_proc -public pm::project::name {
+ -project_item_id:required
+} {
+ Returns the name for a project
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-07-01
+
+ @param project_item_id
+
+ @return
+
+ @error
+} {
+ return [db_string get_name {
+ SELECT
+ title
+ FROM
+ cr_revisions p,
+ cr_items i
+ WHERE
+ i.live_revision = p.revision_id
+ and i.item_id = :project_item_id
+ } -default ""]
+}
+
+
+ad_proc -public pm::project::url {
+ -project_item_id:required
+} {
+ Returns the URL for a project, when given the project_item_id
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-07-01
+
+ @param project_item_id
+
+ @return
+
+ @error
+} {
+
+ return "[ad_url][ad_conn package_url]one?project_item_id=$project_item_id"
+
+}
+
+
+ad_proc -public pm::project::one_default_orderby {
+ {-set ""}
+} {
+ Returns the default order by (set by ad_set_client_property)
+
+ @author (jader@bread.com)
+ @creation-date 2004-11-04
+
+ @param if set is set, then set the default_orderby
+
+ @return
+
+ @error
+} {
+ if {[empty_string_p $set]} {
+
+ set default_orderby "latest_start,asc"
+
+ set return_val [ad_get_client_property \
+ -default $default_orderby \
+ -- \
+ project-manager \
+ project-one-orderby]
+
+ return $return_val
+
+ } else {
+
+ ad_set_client_property -- project-manager project-one-orderby $set
+ return $set
+
+ }
+}
+
+
+ad_proc -public pm::project::index_default_orderby {
+ {-set ""}
+} {
+ Returns the default order by (set by ad_set_client_property)
+
+ @author (jader@bread.com)
+ @creation-date 2004-11-04
+
+ @param if set is set, then set the default_orderby
+
+ @return
+
+ @error
+} {
+ if {[empty_string_p $set]} {
+
+ set default_orderby "project_name,asc"
+
+ set return_val [ad_get_client_property \
+ -default $default_orderby \
+ -- \
+ project-manager \
+ project-index-orderby]
+
+ return $return_val
+
+ } else {
+
+ ad_set_client_property -- project-manager project-index-orderby $set
+ return $set
+
+ }
+}
+
Index: openacs-4/packages/project-manager/tcl/role-procs-oracle.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/tcl/role-procs-oracle.xql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/tcl/role-procs-oracle.xql 29 Apr 2005 17:43:37 -0000 1.1
@@ -0,0 +1,23 @@
+
+
+
+ oracle8.0
+
+
+
+ SELECT role_id
+ FROM pm_roles
+ WHERE rownum = 1
+
+
+
+
+
+
+ SELECT one_line || ' (' || substr(one_line,1,1) || ')' as one_line,
+ role_id
+ FROM pm_roles
+ ORDER BY role_id
+
+
+
Index: openacs-4/packages/project-manager/tcl/role-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/tcl/role-procs.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/tcl/role-procs.tcl 29 Apr 2005 17:43:37 -0000 1.1
@@ -0,0 +1,310 @@
+#
+
+ad_library {
+
+ Procs for roles
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-04-05
+ @arch-tag: 226cb104-9e32-4de3-9f93-ab96e239ca93
+ @cvs-id $Id: role-procs.tcl,v 1.1 2005/04/29 17:43:37 timoh Exp $
+}
+
+
+namespace eval pm::role {}
+
+ad_proc -public pm::role::default {
+} {
+ Gets the default role. This is pretty much random, but the first
+ role selected
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-04-05
+
+ @return role_id
+
+ @error -1 if there is an error.
+} {
+ set returnval [db_string get_default "select role_id from pm_roles limit 1" -default "-1"]
+ return $returnval
+}
+
+
+ad_proc -public pm::role::select_list_filter {} {
+ Returns a select list.
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-06-11
+
+ @return
+
+ @error
+} {
+ return [util_memoize [list pm::role::select_list_filter_not_cached] 300]
+}
+
+
+ad_proc -private pm::role::select_list_filter_not_cached {} {
+ Returns a select list. Used so pm::role::select_list can be cached.
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-06-11
+
+ @return
+
+ @error
+} {
+ return [db_list_of_lists get_roles "
+ SELECT
+ one_line || ' (' || substring(one_line from 1 for 1) || ')' as one_line,
+ role_id
+ FROM
+ pm_roles
+ ORDER BY
+ role_id"]
+}
+
+
+ad_proc -public pm::role::select_list {
+ {-select_name:required}
+} {
+ Returns a select list, suitable for use in an HTML form.
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-06-11
+
+ @return
+
+ @error
+} {
+ set select_list ""
+
+ return $select_list
+}
+
+
+ad_proc -public pm::role::project_select_list_filter {
+ -project_item_id:required
+ -party_id:required
+} {
+ Returns a select list.
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-06-11
+
+ @param project_item_id
+
+ @param party_id
+
+ @return
+
+ @error
+} {
+ return [util_memoize [list pm::role::project_select_list_filter_not_cached -project_item_id $project_item_id -party_id $party_id] 300]
+}
+
+
+ad_proc -private pm::role::project_select_list_filter_not_cached {
+ -project_item_id:required
+ -party_id:required
+} {
+ Returns a select list. Used so pm::role::project_select_list can be cached.
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-06-11
+
+ @param project_item_id
+
+ @param party_id
+
+ @return
+
+ @error
+} {
+ return [db_list_of_lists get_roles "
+ SELECT
+ one_line || ' (' || substring(one_line from 1 for 1) || ')' as one_line,
+ role_id
+ FROM
+ pm_roles as r
+ WHERE NOT EXISTS
+ (SELECT 1
+ FROM
+ pm_project_assignment as pa
+ WHERE
+ r.role_id = pa.role_id and
+ pa.project_id = :project_item_id and
+ pa.party_id = :party_id)
+ ORDER BY
+ role_id"]
+}
+
+
+ad_proc -public pm::role::project_select_list {
+ {-select_name:required}
+ {-project_item_id:required}
+ {-party_id:required}
+} {
+ Returns a select list, suitable for use in an HTML form.
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-06-11
+
+ @return
+
+ @error
+} {
+ set select_list ""
+
+ return $select_list
+}
+
+
+ad_proc -public pm::role::task_select_list_filter {
+ -task_item_id:required
+ -party_id:required
+} {
+ Returns a select list.
+
+ @author Richard Hamilton (ricky.hamilton@btopenworld.com)
+ @creation-date 2004-12-18
+
+ @param task_item_id
+
+ @param party_id
+
+ @return
+
+ @error
+} {
+ return [util_memoize [list pm::role::task_select_list_filter_not_cached -task_item_id $task_item_id -party_id $party_id] 300]
+}
+
+
+ad_proc -private pm::role::task_select_list_filter_not_cached {
+ -task_item_id:required
+ -party_id:required
+} {
+ Returns a select list. Used so pm::role::task_select_list can be cached.
+
+ @author Richard Hamilton (ricky.hamilton@btopenworld.com)
+ @creation-date 2004-12-18
+
+ @param task_item_id
+
+ @param party_id
+
+ @return
+
+ @error
+} {
+ return [db_list_of_lists get_roles "
+ SELECT
+ one_line || ' (' || substring(one_line from 1 for 1) || ')' as one_line,
+ role_id
+ FROM
+ pm_roles as r
+ WHERE NOT EXISTS
+ (SELECT 1
+ FROM
+ pm_task_assignment as ta
+ WHERE
+ r.role_id = ta.role_id and
+ ta.task_id = :task_item_id and
+ ta.party_id = :party_id)
+ ORDER BY
+ role_id"]
+}
+
+
+ad_proc -public pm::role::task_select_list {
+ {-select_name:required}
+ {-task_item_id:required}
+ {-party_id:required}
+} {
+ Returns a select list, suitable for use in an HTML form.
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-06-11
+
+ @return
+
+ @error
+} {
+ set select_list ""
+
+ return $select_list
+}
+
+
+ad_proc -public pm::role::name {
+ -role_id:required
+} {
+ Returns the one_line for the role from the role_id
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-09-08
+
+ @param role_id
+
+ @return one_line
+
+ @error
+} {
+ return [util_memoize [list pm::role::name_not_cached -role_id $role_id]]
+}
+
+
+ad_proc -public pm::role::name_not_cached {
+ -role_id:required
+} {
+ Returns the one_line for the role from the role_id
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-09-08
+
+ @param role_id
+
+ @return one_line
+
+ @error
+} {
+ return [db_string get_one_line {
+ SELECT
+ one_line
+ FROM
+ pm_roles
+ WHERE
+ role_id = :role_id
+ } -default "error"]
+}
Index: openacs-4/packages/project-manager/tcl/status-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/tcl/status-procs.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/tcl/status-procs.tcl 29 Apr 2005 17:43:37 -0000 1.1
@@ -0,0 +1,124 @@
+#
+
+ad_library {
+
+ Procs for project manager status codes and so on.
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-05-21
+ @arch-tag: 23a501b5-de19-4d4a-ad9f-57dfa5c8bbd3
+ @cvs-id $Id: status-procs.tcl,v 1.1 2005/04/29 17:43:37 timoh Exp $
+}
+
+namespace eval pm::status {}
+
+ad_proc -public pm::status::open_p {
+ -task_status_id:required
+} {
+ Returns t if the task status code is open, f otherwise
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-05-21
+
+ @param task_status_id
+
+ @return
+
+ @error
+} {
+
+ set return_val [db_string get_open_p {
+ SELECT
+ case when status_type = 'c' then 'f' else 't' end
+ FROM
+ pm_task_status
+ WHERE
+ status_id = :task_status_id
+ }]
+
+ return $return_val
+}
+
+
+ad_proc -public pm::status::default_closed { } {
+ Returns a default project_status id that is closed
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-07-02
+
+ @param task_status_id
+
+ @return
+
+ @error
+} {
+
+ set return_val [db_string get_closed_status {
+ SELECT
+ status_id
+ FROM
+ pm_project_status
+ WHERE
+ status_type = 'c'
+ LIMIT 1
+ }]
+
+ return $return_val
+}
+
+
+ad_proc -public pm::status::default_open { } {
+ Returns a default project_status id that is open
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-09-17
+
+ @param status_id
+
+ @return
+
+ @error
+} {
+
+ set return_val [db_string get_open_status {
+ SELECT
+ status_id
+ FROM
+ pm_project_status
+ WHERE
+ status_type = 'o'
+ LIMIT 1
+ }]
+
+ return $return_val
+}
+
+
+ad_proc -public pm::status::project_status_select {
+} {
+ Returns a list of project status codes, suitable for list-builder filters
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-06-11
+
+ @return
+
+ @error
+} {
+ return [util_memoize [list pm::status::project_status_select_helper] 300]
+}
+
+
+ad_proc -private pm::status::project_status_select_helper {
+} {
+ Returns a list of project status codes, suitable for list-builder filters
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-06-11
+
+ @return
+
+ @error
+} {
+ return [db_list_of_lists get_status "select description, status_id from pm_project_status order by status_type desc, description"]
+}
Index: openacs-4/packages/project-manager/tcl/task-procs-oracle.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/tcl/task-procs-oracle.xql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/tcl/task-procs-oracle.xql 29 Apr 2005 17:43:37 -0000 1.1
@@ -0,0 +1,126 @@
+
+
+
+ oracle8.0
+
+
+
+ SELECT i.item_id
+ FROM cr_items i,
+ cr_revisions r
+ WHERE i.item_id = r.item_id and
+ r.revision_id = :task_id
+
+
+
+
+
+ SELECT live_revision
+ FROM cr_items i
+ WHERE i.item_id = :task_item_id
+
+
+
+
+
+ select status
+ from pm_tasks
+ where task_id = :task_item_id
+
+
+
+
+
+ SELECT case when status_type = 'c'
+ then 0
+ else 1 end as open_p
+ FROM pm_tasks t,
+ pm_task_status s
+ WHERE task_id = :task_item_id and
+ t.status = s.status_id
+
+
+
+
+
+ select status_id
+ from pm_task_status
+ where status_type = 'o' and
+ rownum = 1
+
+
+
+
+
+ select status_id
+ from pm_task_status
+ where status_type = 'c' and
+ rownum = 1
+
+
+
+
+
+ SELECT r.item_id,
+ r.title as task_title
+ FROM pm_tasks_revisionsx r,
+ cr_items i,
+ pm_tasks t,
+ pm_task_status s
+ WHERE r.parent_id = :project_item_id and
+ r.revision_id = i.live_revision and
+ i.item_id = t.task_id and
+ t.status = s.status_id and
+ s.status_type = 'o'
+ $union_clause
+ ORDER BY task_title
+
+
+
+
+
+ begin
+ :1 := pm_task.new_task_revision (
+ p_task_id => :task_item_id,
+ p_project_id => :project_item_id,
+ p_title => :title,
+ p_description => :description,
+ p_mime_type => :mime_type,
+ p_end_date => [pm::util::datenvl -value $end_date -value_if_null "null" -value_if_not_null "to_timestamp('$end_date','YYYY MM DD HH24 MI SS')"],
+ p_percent_complete => :percent_complete,
+ p_estimated_hours_work => :estimated_hours_work,
+ p_estimated_hours_work_min => :estimated_hours_work_min,
+ p_estimated_hours_work_max => :estimated_hours_work_max,
+ p_actual_hours_worked => :actual_hours_worked,
+ p_status_id => :status_id,
+ p_creation_date => sysdate ,
+ p_creation_user => :update_user,
+ p_creation_ip => :update_ip,
+ p_package_id => :package_id);
+ end;
+
+
+
+
+
+ begin
+ :1 := pm_task.new_task_item (
+ p_project_id => :project_id,
+ p_title => :title,
+ p_description => :description,
+ p_mime_type => :mime_type,
+ p_end_date => [pm::util::datenvl -value $end_date -value_if_null "null" -value_if_not_null "to_timestamp('$end_date','YYYY MM DD HH24 MI SS')"],
+ p_percent_complete => :percent_complete,
+ p_estimated_hours_work => :estimated_hours_work,
+ p_estimated_hours_work_min => :estimated_hours_work_min,
+ p_estimated_hours_work_max => :estimated_hours_work_max,
+ p_status_id => :status_id,
+ p_creation_date => :creation_date,
+ p_creation_user => :creation_user,
+ p_creation_ip => :creation_ip,
+ p_package_id => :package_id);
+ end;
+
+
+
+
Index: openacs-4/packages/project-manager/tcl/task-procs-postgresql.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/tcl/task-procs-postgresql.xql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/tcl/task-procs-postgresql.xql 29 Apr 2005 17:43:37 -0000 1.1
@@ -0,0 +1,385 @@
+
+
+
+ postgresql7.3
+
+
+
+ SELECT
+ r.title
+ FROM
+ cr_items i,
+ cr_revisions r
+ WHERE
+ i.item_id = r.item_id and
+ i.item_id = :task_item_id and
+ i.live_revision = r.revision_id
+
+
+
+
+
+ SELECT
+ i.item_id
+ FROM
+ cr_items i,
+ cr_revisions r
+ WHERE
+ i.item_id = r.item_id and
+ r.revision_id = :task_id
+
+
+
+
+
+ SELECT
+ live_revision
+ FROM
+ cr_items i
+ WHERE
+ i.item_id = :task_item_id
+
+
+
+
+
+ select status
+ from pm_tasks
+ where task_id = :task_item_id
+
+
+
+
+
+ SELECT
+ case when status_type = 'c' then 0 else 1 end as open_p
+ FROM
+ pm_tasks t,
+ pm_task_status s
+ WHERE
+ task_id = :task_item_id and
+ t.status = s.status_id
+
+
+
+
+
+ select status_id
+ from pm_task_status
+ where status_type = 'o'
+ limit 1
+
+
+
+
+
+ select status_id
+ from pm_task_status
+ where status_type = 'c'
+ limit 1
+
+
+
+
+
+ DELETE FROM
+ pm_task_dependency
+ WHERE
+ task_id = :task_item_id
+
+
+
+
+
+ SELECT
+ task.item_id as t_item_id
+ FROM
+ cr_items task,
+ cr_items project
+ WHERE
+ task.parent_id = project.item_id and
+ project.item_id = :project_item_id
+
+
+
+
+
+ SElECT
+ d.task_id as dep_task,
+ d.parent_task_id as dep_task_parent
+ FROM
+ pm_task_dependency d
+ WHERE
+ d.task_id in ([join $project_tasks ", "])
+
+
+
+
+
+ INSERT INTO
+ pm_task_dependency
+ (dependency_id,
+ task_id,
+ parent_task_id,
+ dependency_type)
+ values
+ (:dependency_id,
+ :task_item_id,
+ :parent_id,
+ 'finish_before_start')
+
+
+
+
+
+ SELECT
+ r.item_id,
+ r.title as task_title
+ FROM
+ pm_tasks_revisionsx r,
+ cr_items i,
+ pm_tasks t,
+ pm_task_status s
+ WHERE
+ r.parent_id = :project_item_id and
+ r.revision_id = i.live_revision and
+ i.item_id = t.task_id and
+ t.status = s.status_id and
+ s.status_type = 'o'
+ $union_clause
+ ORDER BY
+ task_title
+
+
+
+
+
+ SELECT
+ r.item_id,
+ r.title as task_title
+ FROM
+ pm_tasks_revisionsx r,
+ cr_items i,
+ pm_tasks t,
+ pm_task_status s
+ WHERE
+ r.parent_id = :project_item_id and
+ r.revision_id = i.live_revision and
+ i.item_id = t.task_id and
+ t.status = s.status_id and
+ s.status_type = 'o'
+ $union_clause
+ ORDER BY
+ task_title
+
+
+
+
+
+ select pm_task__new_task_revision (
+ :task_item_id,
+ :project_item_id,
+ :title,
+ :description,
+ :mime_type,
+ [pm::util::datenvl -value $end_date -value_if_null "null" -value_if_not_null ":end_date"],
+ :percent_complete,
+ :estimated_hours_work,
+ :estimated_hours_work_min,
+ :estimated_hours_work_max,
+ :actual_hours_worked,
+ :status_id,
+ current_timestamp,
+ :update_user,
+ :update_ip,
+ :package_id,
+ :priority)
+
+
+
+
+
+ UPDATE
+ logger_entries
+ SET
+ project_id = :logger_project
+ WHERE
+ entry_id in
+ (select
+ logger_entry
+ from
+ pm_task_logger_proj_map
+ where
+ task_item_id = :task_item_id)
+
+
+
+
+
+ select pm_task__new_task_item (
+ :project_id,
+ :title,
+ :description,
+ :mime_type,
+ [pm::util::datenvl -value $end_date -value_if_null "null" -value_if_not_null "to_timestamp('$end_date','YYYY MM DD HH24 MI SS')"],
+ :percent_complete,
+ :estimated_hours_work,
+ :estimated_hours_work_min,
+ :estimated_hours_work_max,
+ :status_id,
+ :process_instance_id,
+ coalesce (:creation_date,current_timestamp),
+ :creation_user,
+ :creation_ip,
+ :package_id,
+ :priority)
+
+
+
+
+
+
+ SELECT
+ p.email as from_address,
+ p2.first_names || ' ' || p2.last_name as mod_username
+ FROM
+ parties p,
+ persons p2
+ WHERE
+ p.party_id = :user_id and
+ p.party_id = p2.person_id
+
+
+
+
+
+ SELECT
+ t.title as subject,
+ t.description,
+ t.mime_type as description_mime_type,
+ to_char(t.earliest_start,'MM-DD-YYYY') as earliest_start,
+ to_char(t.earliest_finish,'MM-DD-YYYY') as earliest_finish,
+ to_char(t.latest_start,'MM-DD-YYYY') as latest_start,
+ to_char(t.latest_finish,'MM-DD-YYYY') as latest_finish,
+ t.estimated_hours_work as work,
+ t.estimated_hours_work_min as work_min,
+ t.estimated_hours_work_max as work_max,
+ t.percent_complete,
+ p.title as project_name,
+ t.parent_id as project_item_id,
+ a.process_instance
+ FROM
+ pm_tasks_revisionsx t,
+ pm_tasks_active a,
+ cr_items i,
+ cr_items project,
+ pm_projectsx p
+ WHERE
+ t.item_id = :task_item_id and
+ t.item_id = a.task_id and
+ t.revision_id = i.live_revision and
+ t.item_id = i.item_id and
+ t.parent_id = project.item_id and
+ project.item_id = p.item_id and
+ project.live_revision = p.revision_id
+
+
+
+
+
+ SELECT
+ p.email as to_address,
+ r.one_line as role,
+ r.is_lead_p
+ FROM
+ pm_task_assignment a,
+ parties p,
+ pm_roles r
+ WHERE
+ task_id = :task_item_id and
+ a.party_id = p.party_id and
+ a.role_id = r.role_id
+
+
+
+
+
+
+ SELECT
+ t.title as one_line,
+ t.description,
+ t.mime_type as description_mime_type,
+ t.estimated_hours_work as estimated_hours_work,
+ t.estimated_hours_work_min as estimated_hours_work_min,
+ t.estimated_hours_work_max as estimated_hours_work_max,
+ t.percent_complete,
+ to_char(t.end_date, 'DD') as end_date_day,
+ to_char(t.end_date, 'MM') as end_date_month,
+ to_char(t.end_date, 'YYYY') as end_date_year,
+ d.parent_task_id,
+ i.item_id as tid,
+ t.parent_id as project,
+ t.priority
+ FROM
+ pm_tasks_revisionsx t,
+ cr_items i
+ LEFT JOIN
+ pm_task_dependency d
+ ON i.item_id = d.task_id
+ WHERE
+ t.revision_id = i.live_revision and
+ t.item_id = i.item_id
+ $task_where_clause
+
+
+
+
+
+
+ SELECT
+ party_id,
+ role_id
+ FROM
+ pm_task_assignment
+ WHERE
+ task_id = :task_item_id
+
+
+
+
+
+
+ UPDATE
+ pm_tasks
+ SET
+ status = :status_code
+ WHERE
+ task_id = :task_item_id
+
+
+
+
+
+ UPDATE
+ pm_tasks
+ SET
+ status = :status_code
+ WHERE
+ task_id = :task_item_id
+
+
+
+
+
+ SELECT
+ p.first_names || ' ' || p.last_name
+ FROM
+ pm_task_assignment a,
+ persons p
+ WHERE
+ task_id = :task_item_id and
+ a.party_id = p.person_id
+
+
+
+
Index: openacs-4/packages/project-manager/tcl/task-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/project-manager/tcl/task-procs.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/project-manager/tcl/task-procs.tcl 29 Apr 2005 17:43:37 -0000 1.1
@@ -0,0 +1,2647 @@
+ad_library {
+
+ Project Manager Projects Library
+
+ Procedures that deal with tasks
+
+ @creation-date 2003-12-18
+ @author Jade Rubick
+ @cvs-id $Id: task-procs.tcl,v 1.1 2005/04/29 17:43:37 timoh Exp $
+
+}
+
+namespace eval pm::task {}
+
+
+ad_proc -public pm::task::name {
+ {-task_item_id:required}
+} {
+ Returns the name of the task
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-10-25
+
+ @param task_item_id
+
+ @return
+
+ @error -1
+} {
+ return [db_string get_name { } -default "-1"]
+}
+
+
+ad_proc -public pm::task::options_list {
+ {-edit_p "f"}
+ -project_item_id
+ {-task_item_id ""}
+ {-dependency_task_ids ""}
+ {-number "0"}
+ {-current_number "0"}
+} {
+ Returns a list of lists suitable for use in a select list for
+ ad_form. Contains a list of possible tasks that this task can
+ depend upon, or selected. These tasks are limited to just the
+ one project.
+
+
+
+ There is one special case that we handle: if you are creating new
+ tasks (not editing), you can have them depend on each other.
+ So if you create two tasks at the same time, you may want task
+ 2 to depend on task 1. Instead of a task_item_id, we then
+ specify a value of this form:
+
+
+ numX
+
+
+ where X represents the number of the new task, ranging from 1
+ to n.
+
+
+
+ To be more efficient when creating multiple tasks at the same
+ time, we should cache the database calls.
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-05-13
+
+ @param edit_p Is this for a task being edited? Or a new task?
+
+ @param project_item_id The project we're finding tasks from
+
+ @param task_item_id The task ID. This is used because we do not
+ want a task to depend on itself, so it is excluded from the list.
+
+ @param dependency_task_ids For edited tasks, the current task_ids
+ that it depends on. Used because sometimes it can be closed, and
+ it wouldn't otherwise appear on the list. This is a list.
+
+ @param number When the list is returned, it includes entries for
+ number new tasks, in the numX format described in these docs.
+
+ @param current_number The current number. Used for new tasks. It
+ prevents allowing dependencies on the task being created.
+
+ @return
+
+ @error
+} {
+
+ # get tasks this task can depend on
+
+ if {[exists_and_not_null dependency_task_ids]} {
+
+ set union_clause "
+ UNION
+ SELECT
+ r.item_id,
+ r.title as task_title
+ FROM
+ pm_tasks_revisionsx r,
+ cr_items i,
+ pm_tasks_active t
+ WHERE
+ r.parent_id = :project_item_id and
+ r.revision_id = i.live_revision and
+ i.item_id = t.task_id
+ and t.task_id in ([join $dependency_task_ids ","])"
+ } else {
+ set union_clause ""
+ }
+
+ set keys [list]
+
+ db_foreach get_dependency_tasks { } {
+ set options($task_title) $item_id
+ lappend keys $task_title
+ }
+
+ set keys [lsort $keys]
+
+
+ set dependency_options_full "{\"--None--\" \"\"} "
+
+ if {[string is true $edit_p]} {
+ # Do nothing
+ } else {
+
+ # now set up dependency options
+
+ for {set j 1} {$j <= $number} {incr j} {
+ if {![string equal $current_number $j]} {
+ append dependency_options_full "{\"New Task \#$j\" \"num$j\"} "
+ }
+ }
+ }
+
+ # for editing tasks, we skip ourselves (because depending on
+ # ourselves just sometimes isn't an option)
+
+ if {[string is true $edit_p]} {
+ foreach key $keys {
+
+ # make sure we're not dependent on ourselves
+
+ if {![string equal $task_item_id $options($key)]} {
+ # check for case when there is a quote in the name of
+ # a task. We have to filter this out, or we get an error.
+ append dependency_options_full "{{$key} $options($key)} "
+ }
+ }
+ } else {
+ foreach key $keys {
+
+ # check for case when there is a quote in the name of
+ # a task. We have to filter this out, or we get an error.
+ append dependency_options_full "{{$key} $options($key)} "
+ }
+ }
+
+
+ return $dependency_options_full
+}
+
+
+ad_proc -public pm::task::options_list_html {
+ {-edit_p "f"}
+ -project_item_id
+ {-task_item_id ""}
+ {-dependency_task_id ""}
+ {-dependency_task_ids ""}
+ {-number "0"}
+ {-depends_on_new ""}
+ {-current_number "0"}
+} {
+ Returns a list of options suiteable for HTML.
+ Contains a list of possible tasks that this task can
+ depend upon, or selected. These tasks are limited to just the
+ one project.
+
+
+
+ There is one special case that we handle: if you are creating new
+ tasks (not editing), you can have them depend on each other.
+ So if you create two tasks at the same time, you may want task
+ 2 to depend on task 1. Instead of a task_item_id, we then
+ specify a value of this form:
+
+
+ numX
+
+
+ where X represents the number of the new task, ranging from 1
+ to n.
+
+
+
+ To be more efficient when creating multiple tasks at the same
+ time, we should cache the database calls.
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-05-13
+
+ @param edit_p Is this for a task being edited? Or a new task?
+
+ @param project_item_id The project we're finding tasks from
+
+ @param task_item_id The task ID. This is used because we do not
+ want a task to depend on itself, so it is excluded from the list.
+
+ @param dependency_task_ids For edited tasks, the current task_ids
+ that it depends on. Used because sometimes it can be closed, and
+ it wouldn't otherwise appear on the list. This is a list.
+
+ @param dependency_task_id For edited tasks, the current task that
+ it depends on, used for setting the default option in HTML.
+
+ @param number When the list is returned, it includes entries for
+ number new tasks, in the numX format described in these docs.
+
+ @param depends_on_new When you're using a process, you want the
+ dependency to be on other new tasks. The format for this should
+ be num1 num2, etc.. So we make the default if this parameter is set.
+
+ @param current_number The current number. Used for new tasks. It
+ prevents allowing dependencies on the task being created.
+
+ @return
+
+ @error
+} {
+
+ # get tasks this task can depend on
+
+ if {[exists_and_not_null dependency_task_ids]} {
+
+ set union_clause "
+ UNION
+ SELECT
+ r.item_id,
+ r.title as task_title
+ FROM
+ pm_tasks_revisionsx r,
+ cr_items i,
+ pm_tasks_active t
+ WHERE
+ r.parent_id = :project_item_id and
+ r.revision_id = i.live_revision and
+ i.item_id = t.task_id
+ and t.task_id in ([join $dependency_task_ids ","])"
+ } else {
+ set union_clause ""
+ }
+
+ set keys [list]
+
+ db_foreach get_dependency_tasks { } {
+ set options($task_title) $item_id
+ lappend keys $task_title
+ }
+
+ set keys [lsort $keys]
+
+ # ---------------------------------------------------------------
+ # Start setting up the output.
+ # These are for new tasks, the already created tasks are added to
+ # the list later.
+ # ---------------------------------------------------------------
+
+ set dependency_options_full " "
+
+ if {[string is false $edit_p]} {
+
+ # now set up dependency options
+
+ for {set j 1} {$j <= $number} {incr j} {
+
+ if {[string equal $depends_on_new $j]} {
+ set selected "selected=\"selected\" "
+ } else {
+ set selected ""
+ }
+
+ if {![string equal $current_number $j]} {
+ append dependency_options_full " "
+ }
+ }
+ }
+
+ # -------------------------------------------------
+ # Now add the tasks that are already in the project
+ # -------------------------------------------------
+
+
+ if {[string is true $edit_p]} {
+ foreach key $keys {
+
+ # for editing tasks, we skip ourselves (because depending on
+ # ourselves just sometimes isn't an option)
+ if {![string equal $task_item_id $options($key)]} {
+
+ if {[string equal $options($key) $dependency_task_id]} {
+ set selected "selected=\"selected\" "
+ } else {
+ set selected ""
+ }
+
+ # check for case when there is a quote in the name of
+ # a task. We have to filter this out, or we get an
+ # error. -- not sure what this comment is for -- JR
+
+
+ append dependency_options_full " "
+ }
+ }
+ } else {
+
+ foreach key $keys {
+
+ # check for case when there is a quote in the name of a
+ # task. We have to filter this out, or we get an error. --
+ # not sure what this comment is for -- JR
+
+ append dependency_options_full " "
+ }
+ }
+
+
+ return $dependency_options_full
+}
+
+
+ad_proc -public pm::task::dependency_delete_all {
+ -task_item_id:required
+
+} {
+ Deletes all the dependencies of a task
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-02-23
+
+ @param task_item_id The task we wish to remove the dependencies from.
+
+ @return
+
+ @error
+} {
+ db_dml delete_deps { }
+
+ return 1
+}
+
+
+ad_proc -public pm::task::dependency_add {
+ -task_item_id:required
+ -parent_id:required
+ -dependency_type:required
+ -project_item_id:required
+} {
+
+ Adds a dependency to a task, checking for loops in the process
+
+
+
+ We make the assumption that the following is true:
+
+
+
no loop is created if you depend on a task already present
+
therefore, if you add a task without creating a loop in the
+ newly created tasks, you are safe.
+
+
+ We check that the new items don't depend on each other by
+ following them if they loop more than the number of tasks in the
+ project, then we have a loop
+
+
+ The way we check for a loop is to follow the dependencies
+ until we get to a task that has already been created.
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-02-23
+
+ @param task_item_id The task that is trying to create a
+ dependency. Of course this means that the task has already been
+ created.
+
+ @param parent_id The task that we would like to create a
+ dependency on. (item_id for task, of course)
+
+ @param dependency_type Type of dependency, from pm_dependency_types
+
+ @param project_item_id The project's item_id. All dependencies are
+ created within this project
+
+ @return
+
+ @error
+} {
+
+ set project_tasks [db_list get_tasks { }]
+
+ # we do not allow tasks to depend on items outside of their
+ # project. So if it's not in the list of tasks for that project,
+ # we reject it
+
+ if {[lsearch $project_tasks $parent_id] < 0} {
+ set loop_limit 0
+ set valid_p FALSE
+ } else {
+ set loop_limit [llength $project_tasks]
+ }
+
+ if {$loop_limit > 0} {
+
+ set dep_list [list]
+ db_foreach get_dependencies { } {
+ lappend dep_list d-$dep_task-$dep_task_parent
+ }
+
+ # are there any loops?
+ lappend dep_list d-$task_item_id-$parent_id
+
+ foreach ti $project_tasks {
+ set task_state($ti) 0
+ }
+ nsv_array set task_node_status [array get task_state]
+
+
+ set valid_p [pm::task::verify_no_loops \
+ -current_task $task_item_id \
+ -dependency_list $dep_list]
+
+ }
+
+ if {[string is true $valid_p]} {
+ # after it passes
+ set dependency_id [db_nextval pm_task_dependency_seq]
+
+ db_dml insert_dep { }
+
+ } else {
+ ns_log Notice "Task dependency for $task_item_id on $parent_id was not added due to looping or being outside of the current project"
+ }
+
+}
+
+
+ad_proc -private pm::task::verify_no_loops {
+ {-current_task:required}
+ {-dependency_list:required}
+} {
+ Based on the dag_dfs algorithm at http://wiki.tcl.tk/3716
+
+
+
+ Determines if adding in the additional dependency would create
+ an cyclical graph or not
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-02-25
+
+ @param project_task_list
+
+ @param current_task
+
+ @param dependency_list a list of dependencies, each of the form
+ d-n1-n2 where n1 is the child and n2 is the parent. The initial
+ call to this function should include the proposed addition in
+ this list.
+
+ @return TRUE if no loops, FALSE if the proposed additon would add loops
+
+ @error
+} {
+
+ set return_val ""
+
+ array set task_state [nsv_array get task_node_status]
+
+ set task_state($current_task) 1
+
+ nsv_array set task_node_status [array get task_state]
+
+ foreach arc $dependency_list {
+ regexp {d-(.*)-(.*)} $arc match child parent
+
+ # only walk to dependencies from the current task
+ if {[string equal $child $current_task]} {
+
+ set tNode $parent
+
+ array set task_state [nsv_array get task_node_status]
+
+ # this should only happen if dependencies span projects
+ # they shouldn't, but I check anyway.
+ if {![info exists task_state($tNode)]} {
+ set used 0
+ } else {
+ set used $task_state($tNode)
+ }
+
+ if {[string equal $used 1]} {
+ return FALSE
+ }
+
+ set return_val [pm::task::verify_no_loops \
+ -current_task $parent \
+ -dependency_list $dependency_list
+ ]
+
+ if {[string equal $return_val FALSE]} {
+ return FALSE
+ }
+ }
+
+ }
+
+ array set task_state [nsv_array get task_node_status]
+
+ set task_state($current_task) 2
+
+ nsv_array set task_node_status [array get task_state]
+
+ return TRUE
+}
+
+
+
+ad_proc -public pm::task::get_item_id {
+ -task_id:required
+} {
+ Returns the task_item_id (item_id) when given the task_id (revision_id)
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-02-19
+
+ @param task_id The revision item
+
+ @return task_item_id
+
+ @error Returns -1 if there is no such task
+} {
+ set return_val [db_string get_item_id { } -default "-1"]
+
+ return $return_val
+}
+
+
+
+ad_proc -public pm::task::get_revision_id {
+ -task_item_id:required
+} {
+ Returns task_id (revision_id) when given the task_item_id (item_id)
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-02-19
+
+ @param task_item_id The revision item
+
+ @return task_item_id
+
+ @error If there is no such task item, then returns -1
+} {
+ set return_val [db_string get_revision_id { } -default "-1"]
+
+ return $return_val
+}
+
+
+
+ad_proc -public pm::task::current_status {
+ -task_item_id:required
+} {
+ Returns the current status value for open tasks
+} {
+ set return_val [db_string get_current_status { }]
+
+ return $return_val
+}
+
+
+ad_proc -public pm::task::open_p {
+ -task_item_id:required
+} {
+ Returns 1 if the task is open, 0 otherwise
+} {
+ set return_val [db_string open_p { }]
+
+ return $return_val
+}
+
+
+ad_proc -public pm::task::default_status_open {} {
+ Returns the default status value for open tasks
+} {
+ set return_val [db_string get_default_status_open { }]
+
+ return $return_val
+}
+
+
+ad_proc -public pm::task::default_status_closed {} {
+ Returns the default status value for closed tasks
+} {
+ set return_val [db_string get_default_status_closed { }]
+
+ return $return_val
+}
+
+
+
+ad_proc -public pm::task::edit {
+ -task_item_id:required
+ -project_item_id:required
+ -title:required
+ -description:required
+ {-mime_type "text/plain"}
+ {-comment ""}
+ {-comment_type "text/plain"}
+ -end_date:required
+ -percent_complete:required
+ -estimated_hours_work:required
+ -estimated_hours_work_min:required
+ -estimated_hours_work_max:required
+ -update_user:required
+ -update_ip:required
+ -package_id:required
+ {-priority "0"}
+} {
+
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-02-23
+
+ @param task_item_id
+
+ @param project_item_id
+
+ @param title
+
+ @param description
+
+ @param comment The comment to send out by email if the task
+ is closed. Otherwise, it is NOT sent out.
+
+ @param mime_type
+
+ @param end_date
+
+ @param percent_complete
+
+ @param estimated_hours_work
+
+ @param estimated_hours_work_min
+
+ @param estimated_hours_work_max
+
+ @param update_user The user updating the task
+
+ @param update_ip The IP address of the request
+
+ @param package_id
+
+ @return new revision_id for the task
+
+ @error
+} {
+ # simple sanity check for min and max estimated hours
+ if {$estimated_hours_work_min > $estimated_hours_work_max} {
+ set temp $estimated_hours_work_max
+ set estimated_hours_work_max $estimated_hours_work_min
+ set estimated_hours_work_min $temp
+ }
+
+ if {$percent_complete >= 100} {
+
+ set status_id [pm::task::default_status_closed]
+
+ } elseif {$percent_complete < 100} {
+
+ set status_id [pm::task::default_status_open]
+ }
+
+ set actual_hours_worked [pm::task::update_hours \
+ -task_item_id $task_item_id]
+
+ set return_val [db_exec_plsql new_task_revision { *SQL }]
+
+ # we have to update all logged hours to make sure the hours are
+ # set to the correct project whenever the project is changed.
+
+ set logger_project [pm::project::get_logger_project -project_item_id $project_item_id]
+
+ db_dml update_logger_entries { }
+
+ return $return_val
+}
+
+
+
+ad_proc -public pm::task::new {
+ -project_id:required
+ {-title "Subject missing"}
+ {-description ""}
+ {-mime_type "text/plain"}
+ {-end_date ""}
+ {-percent_complete "0"}
+ {-estimated_hours_work "0"}
+ {-estimated_hours_work_min "0"}
+ {-estimated_hours_work_max "0"}
+ {-creation_date ""}
+ {-status_id ""}
+ {-process_instance_id ""}
+ -creation_user:required
+ -creation_ip:required
+ -package_id:required
+ {-priority "0"}
+} {
+ Creates a new task.
+
+ @param process_instance_id If a process was used to create the
+ task, then it is linked in to that process instance, so we can
+ things like display only tasks that are a part of a process.
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date who knows?
+
+ @return new task_item_id
+
+ @error
+
+} {
+ if {![exists_and_not_null status_id]} {
+ set status_id [pm::task::default_status_open]
+ }
+
+ if {$estimated_hours_work_min > $estimated_hours_work_max} {
+ set temp $estimated_hours_work_max
+ set estimated_hours_work_max $estimated_hours_work_min
+ set estimated_hours_work_min $temp
+ }
+
+ set task_revision [db_exec_plsql new_task_item { *SQL }]
+ set task_item_id [pm::task::get_item_id \
+ -task_id $task_revision]
+
+ if {$percent_complete >= 100} {
+ pm::task::close -task_item_id $task_item_id
+ }
+
+ return $task_item_id
+}
+
+
+
+ad_proc -public pm::task::delete {
+ -task_item_id:required
+} {
+ Marks a task deleted
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-03-10
+
+ @param task_item_id
+
+ @return 1, no matter once
+
+ @error No error thrown if there is no such task.
+} {
+ db_dml mark_delete "update pm_tasks set deleted_p = 't' where task_id = :task_item_id"
+
+ pm::project::compute_status [pm::task::project_item_id -task_item_id $task_item_id]
+
+ return 1
+}
+
+
+ad_proc -public pm::task::project_item_id {
+ -task_item_id:required
+} {
+ Returns the project item id for a given task
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-07-16
+
+ @param task_item_id
+
+ @return -1 if there is an error.
+
+ @error
+} {
+ return [db_string get_project_id "select parent_id from cr_items where item_id = :task_item_id" -default -1]
+}
+
+
+
+ad_proc -public pm::task::get_url {
+ object_id
+} {
+ set url [pm::util::url]
+
+ set package_url "${url}task-one?task_id=$object_id"
+
+ return $package_url
+
+}
+
+
+
+ad_proc -public pm::task::process_reply {
+ reply_id
+} {
+ # return successful_p = "f"
+ return "f"
+}
+
+
+
+ad_proc -public pm::task::slack_time {
+ -earliest_start_j:required
+ -today_j:required
+ -latest_start_j:required
+} {
+ Return the amount of slack time
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-02-20
+
+ @param earliest_start_j Earliest start date, Julian
+
+ @param today_j today's date, in Julian
+
+ @param latest_start_j Latest start date, in Julian
+
+ @return Slack days
+
+ @error
+} {
+ if { \
+ [exists_and_not_null earliest_start_j] && \
+ [exists_and_not_null latest_start_j]} {
+
+ if {$earliest_start_j < $today_j} {
+ set slack_time "[expr $latest_start_j - $today_j] days"
+ } else {
+ set slack_time "[expr $latest_start_j - $earliest_start_j] days"
+ }
+
+ } else {
+ set slack_time "n/a"
+ }
+
+}
+
+
+
+ad_proc -private pm::task::update_hours {
+ {-task_item_id ""}
+ {-task_revision_id ""}
+ {-update_tasks_p "t"}
+} {
+ The pm_tasks_revisions table contains a denormalized cache of the
+ total number of hours logged to it. Updates the cache from the
+ hours logged in logger and the pm_task_logger_proj_map table
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-03-04
+
+ @param task_item_id
+
+ @param task_revision_id
+
+ @param update_tasks_p If t, updates the current pm_tasks_revision
+ table in the database.
+
+ @return total logged hours
+
+ @error if neither task_item_id or task_revision_id is defined,
+ returns -1
+} {
+ if { \
+ ![info exists task_item_id] && \
+ ![info exists task_revision_id]} {
+
+ ns_log Error "Illegal parameters in pm::task::update_hours"
+ return -1
+ }
+
+ if { \
+ [exists_and_not_null task_item_id] && \
+ ![exists_and_not_null task_revision_id]} {
+
+ set task_revision_id [pm::task::get_revision_id \
+ -task_item_id $task_item_id]
+ }
+
+ if { \
+ ![exists_and_not_null task_item_id] && \
+ [exists_and_not_null task_revision_id]} {
+
+ set task_item_id [pm::task::get_item_id \
+ -task_id $task_revision_id]
+ }
+
+
+ set total_logged_hours [db_string total_hours "
+ select sum(le.value) from logger_entries le where entry_id in (select logger_entry from pm_task_logger_proj_map where task_item_id = :task_item_id) and le.variable_id = '[logger::variable::get_default_variable_id]'
+ " -default "0"]
+
+ if {[string is true $update_tasks_p]} {
+
+ db_dml update_current_task {
+ UPDATE
+ pm_tasks_revisions
+ SET
+ actual_hours_worked = :total_logged_hours
+ WHERE
+ task_revision_id = :task_revision_id
+ }
+ }
+
+ return $total_logged_hours
+
+}
+
+
+ad_proc -public pm::task::link {
+ -task_item_id_1:required
+ -task_item_id_2:required
+} {
+ Links two tasks together
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-03-10
+
+ @param task_item_id_1
+
+ @param task_item_id_2
+
+ @return
+
+ @error
+} {
+
+ if {[string equal $task_item_id_1 $task_item_id_2]} {
+ # do nothing
+ ns_log Notice "Project-manager: Cannot link a task to itself!"
+ } elseif {$task_item_id_1 < $task_item_id_2} {
+ db_dml link_tasks "
+ INSERT INTO
+ pm_task_xref
+ (task_id_1, task_id_2)
+ VALUES
+ (:task_item_id_1, :task_item_id_2)"
+ } else {
+ db_dml link_tasks "
+ INSERT INTO
+ pm_task_xref
+ (task_id_1, task_id_2)
+ VALUES
+ (:task_item_id_2, :task_item_id_1)"
+ }
+
+}
+
+
+ad_proc -public pm::task::assign_remove_everyone {
+ -task_item_id:required
+} {
+ Removes all assignments for a task
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-04-09
+
+ @param task_item_id
+
+ @return
+
+ @error
+} {
+
+ db_dml remove_assignment { }
+
+ # Flush the cache that remembers which roles to offer the current user in the 'assign role to myself' listbox
+ util_memoize_flush [list pm::role::task_select_list_filter_not_cached -task_item_id $task_item_id -party_id [ad_conn user_id]]
+}
+
+
+ad_proc -public pm::task::unassign {
+ -task_item_id:required
+ -party_id:required
+} {
+ Removes an assignment for a task
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-11-18
+
+ @param task_item_id
+
+ @param party_id
+
+ @return
+
+ @error
+} {
+ db_dml remove_assignment { }
+
+ # Flush the cache that remembers which roles to offer the current user in the 'assign role to myself' listbox
+ if {[ad_conn user_id] == $party_id} {
+ util_memoize_flush [list pm::role::task_select_list_filter_not_cached -task_item_id $task_item_id -party_id $party_id]
+ }
+}
+
+
+ad_proc -public pm::task::assign {
+ -task_item_id:required
+ -party_id:required
+ {-role_id ""}
+} {
+ Assigns party_id to task_item_id
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-04-05
+
+ @param task_item_id
+
+ @param party_id
+
+ @param role_id the role under which the person is assigned
+
+ @return
+
+ @error
+} {
+ if {![exists_and_not_null role_id]} {
+ set role_id [pm::role::default]
+ }
+
+ db_transaction {
+ # make sure we avoid case when that assignment has already
+ # been made.
+ db_dml delete_assignment {
+ delete from
+ pm_task_assignment
+ where
+ task_id = :task_item_id and
+ party_id = :party_id
+ }
+
+ db_dml add_assignment {
+ insert into pm_task_assignment
+ (task_id,
+ role_id,
+ party_id)
+ values
+ (:task_item_id,
+ :role_id,
+ :party_id)
+ }
+ }
+
+ # Flush the cache that remembers which roles to offer the current user in the 'assign role to myself' listbox
+ if {[ad_conn user_id] == $party_id} {
+ util_memoize_flush [list pm::role::task_select_list_filter_not_cached -task_item_id $task_item_id -party_id $party_id]
+ }
+}
+
+
+ad_proc -public pm::task::assigned_p {
+ -task_item_id:required
+ -party_id:required
+} {
+ Returns 1 if assigned, 0 if not
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-11-18
+
+ @param task_item_id
+
+ @param party_id
+
+ @return
+
+ @error
+} {
+ return [db_string assigned_p { } -default 0]
+}
+
+
+ad_proc -public pm::task::open {
+ {-task_item_id:required}
+} {
+ Opens a task.
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-04-22
+
+ @param task_item_id
+
+ @return
+
+ @error
+} {
+ set status_code [pm::task::default_status_open]
+
+ db_dml update_status { }
+}
+
+ad_proc -public pm::task::close {
+ {-task_item_id:required}
+} {
+ Closes a task
+
+ @author Jade Rubick (jader@bread.com)
+ @creation-date 2004-04-22
+
+ @param task_item_id
+
+ @return
+
+ @error
+} {
+ set status_code [pm::task::default_status_closed]
+
+ db_dml update_status { }
+
+}
+
+
+
+ad_proc -public pm::task::email_status {} {
+
+ set send_email_p [parameter::get_from_package_key -package_key "project-manager" -parameter SendDailyEmail -default "0"]
+
+ if {[string is false $send_email_p]} {
+ ns_log Notice "Parameter SendDailyEmail for project manager says skip email today"
+ return
+ }
+
+ # also don't send reminders on weekends.
+
+ set today_j [db_string get_today "select to_char(current_timestamp,'J')"]
+ if {![pm::project::is_workday_p $today_j]} {
+ return
+ }
+
+ set parties [list]
+
+ # what if the person assigned is no longer a part of the subsite?
+ # right now, we still email them.
+
+ db_foreach get_all_open_tasks {
+ SELECT
+ ts.task_id,
+ ts.task_id as item_id,
+ ts.task_number,
+ t.task_revision_id,
+ t.title,
+ to_char(t.earliest_start,'J') as earliest_start_j,
+ to_char(current_timestamp,'J') as today_j,
+ to_char(t.latest_start,'J') as latest_start_j,
+ to_char(t.latest_start,'YYYY-MM-DD HH24:MI') as latest_start,
+ to_char(t.latest_finish,'YYYY-MM-DD HH24:MI') as latest_finish,
+ t.percent_complete,
+ t.estimated_hours_work,
+ t.estimated_hours_work_min,
+ t.estimated_hours_work_max,
+ case when t.actual_hours_worked is null then 0
+ else t.actual_hours_worked end as actual_hours_worked,
+ to_char(t.earliest_start,'YYYY-MM-DD HH24:MI') as earliest_start,
+ to_char(t.earliest_finish,'YYYY-MM-DD HH24:MI') as earliest_finish,
+ to_char(t.latest_start,'YYYY-MM-DD HH24:MI') as latest_start,
+ to_char(t.latest_finish,'YYYY-MM-DD HH24:MI') as latest_finish,
+ p.first_names || ' ' || p.last_name as full_name,
+ p.party_id,
+ (select one_line from pm_roles r where ta.role_id = r.role_id) as role
+ FROM
+ pm_tasks_active ts,
+ pm_tasks_revisionsx t,
+ pm_task_assignment ta,
+ acs_users_all p,
+ cr_items i,
+ pm_task_status s
+ WHERE
+ ts.task_id = t.item_id and
+ i.item_id = t.item_id and
+ t.task_revision_id = i.live_revision and
+ ts.status = s.status_id and
+ s.status_type = 'o' and
+ t.item_id = ta.task_id and
+ ta.party_id = p.party_id
+ ORDER BY
+ t.latest_start asc
+ } {
+ set earliest_start_pretty [lc_time_fmt $earliest_start "%x"]
+ set earliest_finish_pretty [lc_time_fmt $earliest_finish "%x"]
+ set latest_start_pretty [lc_time_fmt $latest_start "%x"]
+ set latest_finish_pretty [lc_time_fmt $latest_finish "%x"]
+
+ if {[exists_and_not_null earliest_start_j]} {
+ set slack_time [pm::task::slack_time \
+ -earliest_start_j $earliest_start_j \
+ -today_j $today_j \
+ -latest_start_j $latest_start_j]
+
+ }
+
+ if {[lsearch $parties $party_id] == -1} {
+ lappend parties $party_id
+ }
+
+ lappend task_list($party_id) $task_id
+ set titles_arr($task_id) $title
+ set ls_arr($task_id) $latest_start_pretty
+ set lf_arr($task_id) $latest_finish_pretty
+ set slack_arr($task_id) $slack_time
+ set roles($task_id-$party_id) $role
+
+ # how many tasks does this person have?
+ if {[info exists task_count($party_id)]} {
+ incr task_count($party_id)
+ } else {
+ set task_count($party_id) 1
+ }
+ }
+
+ # transitions are < this value
+ set OVERDUE_THRESHOLD 0
+ set PRESSING_THRESHOLD 7
+ set LONGTERM_THRESHOLD 90
+
+ foreach party $parties {
+
+ set subject "Daily Task status report"
+ set address [db_string get_email "select email from parties where party_id = :party" -default "jade-errors@bread.com"]
+
+ set overdue [list]
+ set pressing [list]
+ set longterm [list]
+
+ foreach task $task_list($party) {
+
+ set url [pm::task::get_url $task]
+
+ if {$slack_arr($task) < $OVERDUE_THRESHOLD} {
+ set which_pile overdue
+ } elseif {$slack_arr($task) < $PRESSING_THRESHOLD} {
+ set which_pile pressing
+ } elseif {$slack_arr($task) < $LONGTERM_THRESHOLD} {
+ set which_pile longterm
+ } else {
+ set which_pile ""
+ }
+
+ if {![empty_string_p $which_pile]} {
+
+ lappend $which_pile "
+
The roles people can take on projects and tasks, such as
+ manager, sales contact, tech support person, etc.. Currently,
+ can only be edited directly in the database.
The data model has a facility for default roles, although
+ it is not currently used at all. This shows what is in the
+ database for default roles. Currently unimplemented.
There is a data model for workgroups, but it is not a part
+ of the UI. Shows what is in the database (currently, nothing!)
+
+
+
+
Dependency types
+
No UI
+
When implemented, this page will allow you to view and
+ edit the descriptions given to various dependency types (such
+ as finish before start, etc..) Currently, the only dependency
+ used is finish before start, so it's not exposed in the UI
+
+
+
+
Status types
+
No UI
+
Valid status codes, for example, 'Open' and 'Closed'
Projects can be categorized according to multiple 'trees'
+ of categories. What this means is you can have multiple ways
+ of categorizing your projects. This section sets up your
+ categories and allows you to link them to projects. Currently,
+ there is a bug in the categories package that prevents the
+ context bar at the top of the screen from returning you to the
+ project-manager pages.
Logger is a package that lets you log time, expenses, and
+ other variables. Project manager requires you to
+ install and mount at least one instance of logger, because it
+ uses logger to log time and other variables against projects
+ and tasks. However, you can have varying levels of integration
+ with logger. This section sets up which logger instances you
+ want to be fully integrated with project-manager, so that new
+ project-manager projects appear in the logger instance.
+ @logger_warning;noquote@
+
You must choose a logger instance to be the primary
+ logger linked in with project-manager. This is closely linked
+ in with project-manager, so you can view reports of a project, etc.
+
+ @logger_primary_warning;noquote@
+
Once you have chosen logger instances to be integrated
+ with project-manager, you may have a lot of older
+ project-manager projects that are not synchronized with
+ logger. This page lets you synchronize older project-manager
+ projects with logger, so that they are all linked in correctly
+ with that instance. This does not add in logger projects to
+ project-manager (although someone can certainly add that
+ functionality if they wish).
+
The parameters allow you to do things such as set up daily
+ reminder emails, change what fields are shown in the project
+ view and edit pages, and so on. Highly recommended if you're
+ setting up project-manager.