| 137 | |
| 138 | {{{ |
| 139 | #!py |
| 140 | class ITaskScheduler(Interface): |
| 141 | # Schedule each the ticket in tickets with consideration for |
| 142 | # dependencies, estimated work, hours per day, etc. |
| 143 | # |
| 144 | # Assumes tickets is a list returned by TracPM.query(). |
| 145 | # |
| 146 | # On exit, each ticket has a start and finish that can be accessed |
| 147 | # with TracPM.start() and finish(). No other changes are made. |
| 148 | def scheduleTasks(self, options, tickets): |
| 149 | """Called to schedule tasks""" |
| 150 | }}} |
| 151 | |
| 152 | == Scheduling == |
| 153 | |
| 154 | If the `TicketRescheduler` module is enabled, `TracPM` maintains private tables with task scheduling information. The `schedule` table has the current schedule: |
| 155 | |
| 156 | {{{ |
| 157 | Column | Type | Modifiers |
| 158 | --------+---------+----------- |
| 159 | ticket | integer | not null |
| 160 | start | bigint | |
| 161 | finish | bigint | |
| 162 | Indexes: |
| 163 | "schedule_pkey" PRIMARY KEY, btree (ticket) |
| 164 | "schedule_ticket_idx" btree (ticket) |
| 165 | }}} |
| 166 | |
| 167 | The `schedule_change` table holds a record of changes in the schedule over time. |
| 168 | |
| 169 | {{{ |
| 170 | Column | Type | Modifiers |
| 171 | -----------+---------+----------- |
| 172 | ticket | integer | not null |
| 173 | time | bigint | not null |
| 174 | oldstart | bigint | |
| 175 | oldfinish | bigint | |
| 176 | newstart | bigint | |
| 177 | newfinish | bigint | |
| 178 | Indexes: |
| 179 | "schedule_change_pk" PRIMARY KEY, btree (ticket, "time") |
| 180 | "schedule_change_ticket_idx" btree (ticket) |
| 181 | "schedule_change_time_idx" btree ("time") |
| 182 | }}} |
| 183 | |
| 184 | It is possible -- but not yet supported -- to use the data in `schedule_change` to reconstruct a baseline schedule for an effective date and then report changes from that baseline. |
| 185 | |
| 186 | These tables are maintained by a ticket change listener which looks for changes to fields which might affect schedule then: |
| 187 | |
| 188 | * identifies all tickets that were active (required for an open milestone or an active ticket of the configured milestone ticket type) |
| 189 | * identifies all tickets that are now active (as a result of the changes) |
| 190 | * removes any tickets that were active but are no longer from `schedule` (updating the history in `schedule_change`) |
| 191 | * runs the scheduling algorithm on all tickets that are now active |
| 192 | * writes any changes to `schedule` (updating history in `schedule_change`) |
| 193 | |
| 194 | With this data in place, you can show a Gantt of scheduled tickets with dates as in the database (`[[TracJSGanttChart(scheduled=1)]]`) or create reports of the scheduled tickets. |
| 195 | |
| 196 | {{{ |
| 197 | #!sql |
| 198 | SELECT |
| 199 | p.value AS __color__, |
| 200 | t.id AS ticket, |
| 201 | summary, |
| 202 | priority, |
| 203 | description as _description, |
| 204 | est.value as est, |
| 205 | act.value as act, |
| 206 | -- This bit is specific to Postgres. |
| 207 | (SELECT to_date(to_timestamp((sched.finish/1000000))::text, |
| 208 | 'YYYY-MM-DD')) AS due, |
| 209 | status |
| 210 | FROM ticket AS t |
| 211 | INNER JOIN schedule AS sched ON (t.id=sched.ticket) |
| 212 | INNER JOIN enum AS p ON (p.name=t.priority AND p.type = 'priority') |
| 213 | LEFT OUTER JOIN ticket_custom AS est ON |
| 214 | (t.id=est.ticket AND est.name='estimatedhours') |
| 215 | LEFT OUTER JOIN ticket_custom AS act ON |
| 216 | (t.id=act.ticket AND act.name='totalhours') |
| 217 | WHERE t.owner = '$USER' AND status <> 'closed' |
| 218 | ORDER BY due NULLS FIRST, p.value |
| 219 | }}} |