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

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

Improve TaskService.createSubTask() with sane attribute and collection assignment.

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