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

Last change on this file since 268 was 252, checked in by gav, 15 years ago

Added TaskBudgetStatus as per ticket #49.

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