source: trunk/grails-app/services/TaskService.groovy @ 204

Last change on this file since 204 was 204, checked in by gav, 14 years ago

Refactor taskService update() and enable optimistic version checking.

File size: 20.9 KB
Line 
1/**
2* Provides a service class for the Task domain class.
3*
4*/
5class TaskService {
6
7    boolean transactional = false
8
9    def dateUtilService
10    def personService
11
12    /**
13    * Determines and returns a possible parent list for a task.
14    * @param taskInstance The task to use when determining the possible parent list.
15    * @returns A list of the possible parents.
16    */
17    def possibleParentList(taskInstance) {
18        def criteria = taskInstance.createCriteria()
19        def possibleParentList = criteria {
20            and {
21                notEqual('trash', true)
22                notEqual('id', taskInstance.id)
23                taskInstance.subTasks.each() { notEqual('id', it.id) }
24                }
25        }
26    }
27
28    /**
29    * Creates a new task with the given params.
30    * @param params The params to use when creating the new task.
31    * @returns A map containing result.error=true (if any error) and result.taskInstance.
32    */
33    def create(params) {
34        Task.withTransaction { status ->
35            def result = [:]
36            // Default status to "not started" if not supplied.
37            params.taskStatus = params.taskStatus ?: TaskStatus.get(1)
38            def taskInstance = new Task(params)
39            result.taskInstance = taskInstance
40
41            if(result.taskInstance.parentTask?.trash) {
42                status.setRollbackOnly()
43                result.taskInstance.errors.rejectValue("parentTask", "task.operationNotPermittedOnTaskInTrash")
44                result.error = true
45                return result
46            }
47
48            if(taskInstance.save()) {
49                def taskModification = new TaskModification(person: personService.currentUser(),
50                                                        taskModificationType: TaskModificationType.get(1),
51                                                        task: taskInstance)
52
53                if(!taskModification.save()) {
54                    status.setRollbackOnly()
55                    taskInstance.errors.rejectValue("taskModifications", "task.modifications.failedToSave")
56                    result.error = true
57                    return result
58                }
59
60                // If we get here all went well.
61                return result
62            }
63            else {
64                result.error = true
65                return result
66            }
67
68        } //end withTransaction
69    } // end create()
70
71    /**
72    * Creates a subTask copying attributes from the parentTask unless otherwise specified.
73    * The taskProcedure is only assigned to the sub task if given in params.
74    * @param parentTask The parent task to get attributes from, also set as the parent.
75    * @param params Overrides the parent task values if specified.
76    * @returns A map containing result.error=true (if any error) and result.taskInstance.
77    */
78    def createSubTask(parentTask, params = [:]) {
79
80        def result = [:]
81
82        //Make our new Task a subTask and set the required properites.
83        def p = [:]
84        p.parentTask = parentTask
85        p.description = params.description ?: parentTask.description
86        p.comment = params.comment ?: parentTask.comment
87
88        p.taskGroup = params.taskGroup ?: parentTask.taskGroup
89        p.taskStatus = TaskStatus.get(1) // A new subTask must always be "Not Started".
90        p.taskPriority = parentTask.taskPriority
91        p.taskType = params.taskType ?: parentTask.taskType
92        p.leadPerson = params.leadPerson ?: parentTask.leadPerson
93        p.primaryAsset = params.primaryAsset ?: parentTask.primaryAsset
94
95        p.targetStartDate = params.targetStartDate ?: parentTask.targetStartDate
96        p.targetCompletionDate = params.targetCompletionDate ?: parentTask.targetCompletionDate
97
98        if(params.taskProcedure) p.taskProcedure = params.taskProcedure
99
100                    //Set the assignedPersons
101//                     taskInstance.assignedPersons.each() {
102//
103//                     def assignedPerson = new AssignedPerson(person: it.person,
104//                                                                                             task: subTaskInstance,
105//                                                                                             estimatedHour: it.estimatedHour,
106//                                                                                             estimatedMinute: it.estimatedMinute).save()
107//                     }
108
109        result = create(p)
110
111    } // end createSubTask()
112
113    /**
114    * Creates a new task entry.
115    * @param params The params to use when creating the new entry.
116    * @returns A map containing result.error=true (if any error), result.entryInstance and result.taskId.
117    */
118    def createEntry(params) {
119        Task.withTransaction { status ->
120            def result = [:]
121            result.entryInstance = new Entry(params)
122            result.entryInstance.enteredBy = personService.currentUser()
123
124            if(result.entryInstance.validate()) {
125                result.taskId = result.entryInstance.task.id
126                def taskInstance = Task.lock(result.taskId)
127
128                if(!taskInstance) {
129                    status.setRollbackOnly()
130                    result.entryInstance.errors.rejectValue('task', "task.notFound")
131                    result.error = true
132                    return result
133                }
134
135                if(taskInstance.taskStatus.id == 3) {
136                    status.setRollbackOnly()
137                    result.entryInstance.errors.rejectValue('task', "task.operationNotPermittedOnCompleteTask")
138                    result.error = true
139                    return result
140                }
141
142                // If task status is "Not Started" and entry type is "Work Done" then we create the started modification and set the status.
143                if(taskInstance.taskStatus.id == 1 && result.entryInstance.entryType.id == 2) {
144
145                    // Create the "Started" task modification, this provides the "Actual started date".
146                    def taskModification = new TaskModification(person: personService.currentUser(),
147                                                            taskModificationType: TaskModificationType.get(2),
148                                                            task: taskInstance)
149
150                    if(!taskModification.save()) {
151                        status.setRollbackOnly()
152                        taskInstance.errors.rejectValue("task", "task.modifications.failedToSave")
153                        result.error = true
154                        return result
155                    }
156
157                    // Set task status to "In progress".
158                    taskInstance.taskStatus = TaskStatus.get(2)
159
160                    if(!taskInstance.save()) {
161                        status.setRollbackOnly()
162                        result.entryInstance.errors.rejectValue("task", "task.failedToSave")
163                        result.error = true
164                        return result
165                    }
166                }
167
168                if(!result.entryInstance.save()) {
169                    status.setRollbackOnly()
170                    result.error = true
171                    return result
172                }
173
174                // If we get here all went well.
175                return result
176            }
177            else {
178                result.error = true
179                return result
180            }
181
182        } //end withTransaction
183    } // end create()
184
185    /**
186    * Updates an existing task.
187    * @param params The params to update for task with id of params.id.
188    * @returns A map containing result.error=true (if any error) and result.taskInstance (if available).
189    */
190    def update(params) {
191        Task.withTransaction { status ->
192            def result = [:]
193
194            def fail = { Object[] args ->
195                status.setRollbackOnly()
196                if(args.size() == 2) result.taskInstance.errors.rejectValue(args[0], args[1])
197                result.error = true
198                return result
199            }
200
201            result.taskInstance = Task.get(params.id)
202
203            if(!result.taskInstance)
204                return fail('task', "task.notFound")
205
206            // Optimistic locking check.
207            if(params.version) {
208                def version = params.version.toLong()
209                if(result.taskInstance.version > version)
210                    return fail("version", "default.optimistic.locking.failure")
211            }
212
213            result.taskInstance.properties = params
214
215            if(result.taskInstance.hasErrors() || !result.taskInstance.save())
216                return fail()
217
218            def taskModification = new TaskModification(person:personService.currentUser(),
219                                                    taskModificationType: TaskModificationType.get(3),
220                                                    task: result.taskInstance)
221
222            if(!taskModification.save())
223                return fail("taskModifications", "task.modifications.failedToSave")
224
225            // If we get here all went well.
226            return result
227
228        } //end withTransaction
229    }  // end update()
230
231    /**
232    * Completes an existing task.
233    * @param params The params for task with id of params.id.
234    * @returns A map containing result.error=true (if any error) and result.taskInstance.
235    */
236    def complete(params) {
237        Task.withTransaction { status ->
238            def result = [:]
239            result.taskInstance = Task.get(params.id)
240            if(result.taskInstance) {
241
242                // Optimistic locking check.
243                if(params.version) {
244                    def version = params.version.toLong()
245                    if(result.taskInstance.version > version) {
246                        status.setRollbackOnly()
247                        result.taskInstance.errors.rejectValue("version", "task.optimistic.locking.failure", "Another user has updated this Task while you were editing.")
248                        result.error = true
249                        return result
250                    }
251                }
252
253                result.taskInstance.taskStatus = TaskStatus.get(3)
254                result.taskInstance.taskRecurringSchedule?.enabled = false
255
256                if(result.taskInstance.save()) {
257                    def taskModification = new TaskModification(person:personService.currentUser(),
258                                                            taskModificationType: TaskModificationType.get(4),
259                                                            task: result.taskInstance)
260
261                    if(taskModification.save()) {
262                        // All went well.
263                        return result
264                    }
265                    else {
266                        status.setRollbackOnly()
267                        result.taskInstance.errors.rejectValue("taskModifications", "task.modifications.failedToSave")
268                        result.error = true
269                        return result
270                    }
271                }
272            }
273            // Something failed.
274            status.setRollbackOnly()
275            result.error = true
276            return result
277
278        } //end withTransaction
279    }  // end complete()
280
281    /**
282    * Reopens an existing task.
283    * @param params The params for task with id of params.id.
284    * @returns A map containing result.error=true (if any error) and result.taskInstance.
285    */
286    def reopen(params) {
287        Task.withTransaction { status ->
288            def result = [:]
289            result.taskInstance = Task.get(params.id)
290            if(result.taskInstance) {
291
292                // Optimistic locking check.
293                if(params.version) {
294                    def version = params.version.toLong()
295                    if(result.taskInstance.version > version) {
296                        status.setRollbackOnly()
297                        result.taskInstance.errors.rejectValue("version", "task.optimistic.locking.failure", "Another user has updated this Task while you were editing.")
298                        result.error = true
299                        return result
300                    }
301                }
302
303                result.taskInstance.taskStatus = TaskStatus.get(2)
304
305                if(result.taskInstance.save()) {
306                    def taskModification = new TaskModification(person:personService.currentUser(),
307                                                            taskModificationType: TaskModificationType.get(5),
308                                                            task: result.taskInstance)
309                    if(taskModification.save()) {
310                        // All went well.
311                        return result
312                    }
313                    else {
314                        status.setRollbackOnly()
315                        result.taskInstance.errors.rejectValue("taskModifications", "task.modifications.failedToSave")
316                        result.error = true
317                        return result
318                    }
319                }
320            }
321            // Something failed.
322            status.setRollbackOnly()
323            result.error = true
324            return result
325
326        } //end withTransaction
327    }  // end reopen()
328
329    /**
330    * Move a task to the trash.
331    * @param params The params for task with id of params.id.
332    * @returns A map containing result.error=true (if any error) and result.taskInstance.
333    */
334    def trash(params) {
335        Task.withTransaction { status ->
336            def result = [:]
337            result.taskInstance = Task.get(params.id)
338            if(result.taskInstance) {
339
340                // Optimistic locking check.
341                if(params.version) {
342                    def version = params.version.toLong()
343                    if(result.taskInstance.version > version) {
344                        status.setRollbackOnly()
345                        result.taskInstance.errors.rejectValue("version", "task.optimistic.locking.failure", "Another user has updated this Task while you were editing.")
346                        result.error = true
347                        return result
348                    }
349                }
350
351                result.taskInstance.trash = true
352                result.taskInstance.taskRecurringSchedule?.enabled = false
353
354                if(result.taskInstance.save()) {
355                    def taskModification = new TaskModification(person:personService.currentUser(),
356                                                            taskModificationType: TaskModificationType.get(6),
357                                                            task: result.taskInstance)
358                    if(taskModification.save()) {
359                        // All went well.
360                        return result
361                    }
362                    else {
363                        status.setRollbackOnly()
364                        result.taskInstance.errors.rejectValue("taskModifications", "task.modifications.failedToSave")
365                        result.error = true
366                        return result
367                    }
368                }
369            }
370            // Something failed.
371            status.setRollbackOnly()
372            result.error = true
373            return result
374
375        } //end withTransaction
376    }  // end trash()
377
378    /**
379    * Restore a task from the trash.
380    * @param params The params for task with id of params.id.
381    * @returns A map containing result.error=true (if any error) and result.taskInstance.
382    */
383    def restore(params) {
384        Task.withTransaction { status ->
385            def result = [:]
386            result.taskInstance = Task.get(params.id)
387            if(result.taskInstance) {
388
389                // Optimistic locking check.
390                if(params.version) {
391                    def version = params.version.toLong()
392                    if(result.taskInstance.version > version) {
393                        status.setRollbackOnly()
394                        result.taskInstance.errors.rejectValue("version", "task.optimistic.locking.failure", "Another user has updated this Task while you were editing.")
395                        result.error = true
396                        return result
397                    }
398                }
399
400                result.taskInstance.trash = false
401
402                if(result.taskInstance.save()) {
403                    def taskModification = new TaskModification(person:personService.currentUser(),
404                                                            taskModificationType: TaskModificationType.get(7),
405                                                            task: result.taskInstance)
406                    if(taskModification.save()) {
407                        // All went well.
408                        return result
409                    }
410                    else {
411                        status.setRollbackOnly()
412                        result.taskInstance.errors.rejectValue("taskModifications", "task.modifications.failedToSave")
413                        result.error = true
414                        return result
415                    }
416                }
417            }
418            // Something failed.
419            status.setRollbackOnly()
420            result.error = true
421            return result
422
423        } //end withTransaction
424    }  // end restore()
425
426    /**
427    * Approve a task.
428    * @param params The params for task with id of params.id.
429    * @returns A map containing result.error=true (if any error) and result.taskInstance.
430    */
431    def approve(params) {
432        Task.withTransaction { status ->
433            def result = [:]
434            result.taskInstance = Task.get(params.id)
435            if(result.taskInstance) {
436
437                // Optimistic locking check.
438                if(params.version) {
439                    def version = params.version.toLong()
440                    if(result.taskInstance.version > version) {
441                        status.setRollbackOnly()
442                        result.taskInstance.errors.rejectValue("version", "task.optimistic.locking.failure", "Another user has updated this Task while you were editing.")
443                        result.error = true
444                        return result
445                    }
446                }
447
448                result.taskInstance.approved = true
449
450                if(result.taskInstance.save()) {
451                    def taskModification = new TaskModification(person:personService.currentUser(),
452                                                            taskModificationType: TaskModificationType.get(8),
453                                                            task: result.taskInstance)
454                    if(taskModification.save()) {
455                        // All went well.
456                        return result
457                    }
458                    else {
459                        status.setRollbackOnly()
460                        result.taskInstance.errors.rejectValue("taskModifications", "task.modifications.failedToSave")
461                        result.error = true
462                        return result
463                    }
464                }
465            }
466            // Something failed.
467            status.setRollbackOnly()
468            result.error = true
469            return result
470
471        } //end withTransaction
472    }  // end approve()
473
474    /**
475    * Remove a previously given approval from a task.
476    * @param params The params for task with id of params.id.
477    * @returns A map containing result.error=true (if any error) and result.taskInstance.
478    */
479    def renegeApproval(params) {
480        Task.withTransaction { status ->
481            def result = [:]
482            result.taskInstance = Task.get(params.id)
483            if(result.taskInstance) {
484
485                // Optimistic locking check.
486                if(params.version) {
487                    def version = params.version.toLong()
488                    if(result.taskInstance.version > version) {
489                        status.setRollbackOnly()
490                        result.taskInstance.errors.rejectValue("version", "task.optimistic.locking.failure", "Another user has updated this Task while you were editing.")
491                        result.error = true
492                        return result
493                    }
494                }
495
496                result.taskInstance.approved = false
497
498                if(result.taskInstance.save()) {
499                    def taskModification = new TaskModification(person:personService.currentUser(),
500                                                            taskModificationType: TaskModificationType.get(9),
501                                                            task: result.taskInstance)
502                    if(taskModification.save()) {
503                        // All went well.
504                        return result
505                    }
506                    else {
507                        status.setRollbackOnly()
508                        result.taskInstance.errors.rejectValue("taskModifications", "task.modifications.failedToSave")
509                        result.error = true
510                        return result
511                    }
512                }
513            }
514            // Something failed.
515            status.setRollbackOnly()
516            result.error = true
517            return result
518
519        } //end withTransaction
520    }  // end renegeApproval()
521
522} // end TaskService
Note: See TracBrowser for help on using the repository browser.