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

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

Record a taskModification for changes to assignedGroups and assignedPersons as per ticket #35.

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