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

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

Added TaskBudgetStatus as per ticket #49.

File size: 24.1 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
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
47            def taskInstance = new Task(params)
48            result.taskInstance = taskInstance
49
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
57            if(taskInstance.save()) {
58                def taskModification = new TaskModification(person: personService.currentUser,
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
69                //Add the assignedGroups, provided by a new ArrayList(task.assignedGroups)
70                if(params.assignedGroups) {
71                    def assignedGroupsResult
72                    def assignedGroupParams = [:]
73                    params.assignedGroups.each() {
74
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) {
83                            status.setRollbackOnly()
84                            taskInstance.errors.rejectValue("assignedGroups", "task.assignedGroups.failedToSave")
85                            result.error = true
86                            return result
87                        }
88
89                    }
90                }
91
92                //Add the assignedPersons, provided by a new ArrayList(task.assignedPersons)
93                if(params.assignedPersons) {
94                    def assignedPersonsResult
95                    def assignedPersonsParams = [:]
96                    params.assignedPersons.each() {
97
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) {
106                            status.setRollbackOnly()
107                            taskInstance.errors.rejectValue("assignedPersons", "task.assignedPersons.failedToSave")
108                            result.error = true
109                            return result
110                        }
111
112                    }
113                }
114
115                // Success.
116                return result
117            }
118            else {
119                result.error = true
120                return result
121            }
122
123        } //end withTransaction
124    } // end create()
125
126    /**
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.
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
146        p.targetStartDate = params.targetStartDate ?: parentTask.targetStartDate
147        p.targetCompletionDate = params.targetCompletionDate ?: parentTask.targetCompletionDate
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
155        p.associatedAssets = params.associatedAssets ?: new ArrayList(parentTask.associatedAssets) // Collection.
156
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
160
161        // Supplied by recurring tasks.
162        if(params.taskProcedure) p.taskProcedure = params.taskProcedure
163        if(params.assignedGroups) p.assignedGroups = params.assignedGroups // Collection.
164        if(params.assignedPersons) p.assignedPersons = params.assignedPersons // Collection.
165
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.
172        result = create(p)
173
174    } // end createSubTask()
175
176    /**
177    * Creates a new task entry.
178    * @param params The params to use when creating the new entry.
179    * @returns A map containing result.error=true (if any error), result.entryInstance and result.taskId.
180    */
181    def createEntry(params) {
182        Task.withTransaction { status ->
183            def result = [:]
184            result.entryInstance = new Entry(params)
185            result.entryInstance.enteredBy = personService.currentUser
186
187            if(result.entryInstance.validate()) {
188                result.taskId = result.entryInstance.task.id
189                def taskInstance = Task.lock(result.taskId)
190
191                if(!taskInstance) {
192                    status.setRollbackOnly()
193                    result.entryInstance.errors.rejectValue('task', "task.notFound")
194                    result.error = true
195                    return result
196                }
197
198                if(taskInstance.taskStatus.id == 3) {
199                    status.setRollbackOnly()
200                    result.entryInstance.errors.rejectValue('task', "task.operationNotPermittedOnCompleteTask")
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".
209                    def taskModification = new TaskModification(person: personService.currentUser,
210                                                            taskModificationType: TaskModificationType.get(2),
211                                                            task: taskInstance)
212
213                    if(!taskModification.save()) {
214                        status.setRollbackOnly()
215                        taskInstance.errors.rejectValue("task", "task.modifications.failedToSave")
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()
225                        result.entryInstance.errors.rejectValue("task", "task.failedToSave")
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
237                // If we get here all went well.
238                return result
239            }
240            else {
241                result.error = true
242                return result
243            }
244
245        } //end withTransaction
246    } // end create()
247
248    /**
249    * Updates an existing task.
250    * @param params The params to update for task with id of params.id.
251    * @returns A map containing result.error=true (if any error) and result.taskInstance (if available).
252    */
253    def update(params) {
254        Task.withTransaction { status ->
255            def result = [:]
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
264            result.taskInstance = Task.get(params.id)
265
266            if(!result.taskInstance)
267                return fail('id', "task.notFound")
268
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            }
275
276            result.taskInstance.properties = params
277
278            if(result.taskInstance.hasErrors() || !result.taskInstance.save())
279                return fail()
280
281            def taskModification = new TaskModification(person:personService.currentUser,
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.
289            return result
290
291        } //end withTransaction
292    }  // end update()
293
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    */
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)
317                result.taskInstance.taskRecurringSchedule?.enabled = false
318
319                if(result.taskInstance.save()) {
320                    def taskModification = new TaskModification(person:personService.currentUser,
321                                                            taskModificationType: TaskModificationType.get(4),
322                                                            task: result.taskInstance)
323
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
342    }  // end complete()
343
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    */
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()) {
369                    def taskModification = new TaskModification(person:personService.currentUser,
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
390    }  // end reopen()
391
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    */
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
415                result.taskInstance.taskRecurringSchedule?.enabled = false
416
417                if(result.taskInstance.save()) {
418                    def taskModification = new TaskModification(person:personService.currentUser,
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
439    }  // end trash()
440
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    */
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()) {
466                    def taskModification = new TaskModification(person:personService.currentUser,
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
487    }  // end restore()
488
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    */
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()) {
514                    def taskModification = new TaskModification(person:personService.currentUser,
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
535    }  // end approve()
536
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    */
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()) {
562                    def taskModification = new TaskModification(person:personService.currentUser,
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
583    }  // end renegeApproval()
584
585} // end TaskService
Note: See TracBrowser for help on using the repository browser.