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
RevLine 
[202]1/**
2* Provides a service class for the Task domain class.
[196]3*
4*/
[137]5class TaskService {
6
[180]7    boolean transactional = false
[137]8
[182]9    def personService
[251]10    def assignedGroupService
11    def assignedPersonService
[137]12
[202]13    /**
[203]14    * Determines and returns a possible parent list for a task.
[245]15    * @todo Create and use another method that limits the results to say the latest 20 or 100 tasks?
[202]16    * @param taskInstance The task to use when determining the possible parent list.
[196]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
[202]30    /**
[196]31    * Creates a new task with the given params.
[202]32    * @param params The params to use when creating the new task.
[196]33    * @returns A map containing result.error=true (if any error) and result.taskInstance.
34    */
[180]35    def create(params) {
36        Task.withTransaction { status ->
37            def result = [:]
[181]38            // Default status to "not started" if not supplied.
39            params.taskStatus = params.taskStatus ?: TaskStatus.get(1)
[180]40            def taskInstance = new Task(params)
41            result.taskInstance = taskInstance
42
[196]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
[180]50            if(taskInstance.save()) {
[216]51                def taskModification = new TaskModification(person: personService.currentUser,
[180]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
[243]62                //Add the assignedGroups, provided by a new ArrayList(task.assignedGroups)
63                if(params.assignedGroups) {
[251]64                    def assignedGroupsResult
65                    def assignedGroupParams = [:]
[243]66                    params.assignedGroups.each() {
67
[251]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) {
[243]76                            status.setRollbackOnly()
77                            taskInstance.errors.rejectValue("assignedGroups", "task.assignedGroups.failedToSave")
78                            result.error = true
79                            return result
80                        }
[251]81
[243]82                    }
83                }
84
85                //Add the assignedPersons, provided by a new ArrayList(task.assignedPersons)
86                if(params.assignedPersons) {
[251]87                    def assignedPersonsResult
88                    def assignedPersonsParams = [:]
[243]89                    params.assignedPersons.each() {
90
[251]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) {
[243]99                            status.setRollbackOnly()
100                            taskInstance.errors.rejectValue("assignedPersons", "task.assignedPersons.failedToSave")
101                            result.error = true
102                            return result
103                        }
[251]104
[243]105                    }
106                }
107
108                // Success.
[180]109                return result
110            }
111            else {
112                result.error = true
113                return result
114            }
115
116        } //end withTransaction
117    } // end create()
118
[202]119    /**
[245]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.
[196]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
[245]139        p.targetStartDate = params.targetStartDate ?: parentTask.targetStartDate
140        p.targetCompletionDate = params.targetCompletionDate ?: parentTask.targetCompletionDate
[196]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
[245]148        p.associatedAssets = params.associatedAssets ?: new ArrayList(parentTask.associatedAssets) // Collection.
[196]149
[245]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
[196]153
[245]154        // Supplied by recurring tasks.
[202]155        if(params.taskProcedure) p.taskProcedure = params.taskProcedure
[245]156        if(params.assignedGroups) p.assignedGroups = params.assignedGroups // Collection.
157        if(params.assignedPersons) p.assignedPersons = params.assignedPersons // Collection.
[202]158
[245]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.
[196]165        result = create(p)
166
167    } // end createSubTask()
168
[202]169    /**
[196]170    * Creates a new task entry.
[202]171    * @param params The params to use when creating the new entry.
[196]172    * @returns A map containing result.error=true (if any error), result.entryInstance and result.taskId.
173    */
[186]174    def createEntry(params) {
175        Task.withTransaction { status ->
176            def result = [:]
177            result.entryInstance = new Entry(params)
[216]178            result.entryInstance.enteredBy = personService.currentUser
[180]179
[186]180            if(result.entryInstance.validate()) {
181                result.taskId = result.entryInstance.task.id
[203]182                def taskInstance = Task.lock(result.taskId)
[186]183
184                if(!taskInstance) {
185                    status.setRollbackOnly()
[203]186                    result.entryInstance.errors.rejectValue('task', "task.notFound")
[186]187                    result.error = true
188                    return result
189                }
190
191                if(taskInstance.taskStatus.id == 3) {
192                    status.setRollbackOnly()
[191]193                    result.entryInstance.errors.rejectValue('task', "task.operationNotPermittedOnCompleteTask")
[186]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".
[216]202                    def taskModification = new TaskModification(person: personService.currentUser,
[186]203                                                            taskModificationType: TaskModificationType.get(2),
204                                                            task: taskInstance)
205
206                    if(!taskModification.save()) {
207                        status.setRollbackOnly()
[203]208                        taskInstance.errors.rejectValue("task", "task.modifications.failedToSave")
[186]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()
[203]218                        result.entryInstance.errors.rejectValue("task", "task.failedToSave")
[186]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
[204]230                // If we get here all went well.
[186]231                return result
232            }
233            else {
234                result.error = true
235                return result
236            }
237
238        } //end withTransaction
239    } // end create()
240
[202]241    /**
242    * Updates an existing task.
243    * @param params The params to update for task with id of params.id.
[204]244    * @returns A map containing result.error=true (if any error) and result.taskInstance (if available).
[202]245    */
[180]246    def update(params) {
247        Task.withTransaction { status ->
248            def result = [:]
[204]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
[180]257            result.taskInstance = Task.get(params.id)
258
[204]259            if(!result.taskInstance)
[206]260                return fail('id', "task.notFound")
[180]261
[204]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            }
[180]268
[204]269            result.taskInstance.properties = params
270
271            if(result.taskInstance.hasErrors() || !result.taskInstance.save())
272                return fail()
273
[216]274            def taskModification = new TaskModification(person:personService.currentUser,
[204]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.
[180]282            return result
283
284        } //end withTransaction
285    }  // end update()
286
[202]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    */
[181]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)
[202]310                result.taskInstance.taskRecurringSchedule?.enabled = false
[181]311
312                if(result.taskInstance.save()) {
[216]313                    def taskModification = new TaskModification(person:personService.currentUser,
[181]314                                                            taskModificationType: TaskModificationType.get(4),
315                                                            task: result.taskInstance)
[201]316
[181]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
[180]335    }  // end complete()
336
[202]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    */
[181]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()) {
[216]362                    def taskModification = new TaskModification(person:personService.currentUser,
[181]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
[180]383    }  // end reopen()
384
[202]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    */
[181]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
[202]408                result.taskInstance.taskRecurringSchedule?.enabled = false
[181]409
410                if(result.taskInstance.save()) {
[216]411                    def taskModification = new TaskModification(person:personService.currentUser,
[181]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
[180]432    }  // end trash()
433
[202]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    */
[181]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()) {
[216]459                    def taskModification = new TaskModification(person:personService.currentUser,
[181]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
[180]480    }  // end restore()
481
[202]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    */
[181]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()) {
[216]507                    def taskModification = new TaskModification(person:personService.currentUser,
[181]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
[180]528    }  // end approve()
529
[202]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    */
[181]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()) {
[216]555                    def taskModification = new TaskModification(person:personService.currentUser,
[181]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
[180]576    }  // end renegeApproval()
577
578} // end TaskService
Note: See TracBrowser for help on using the repository browser.