source: trunk/grails-app/services/TaskSearchService.groovy @ 962

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

Update TaskSearchService.workDone search to include "PM Entries".

File size: 23.8 KB
Line 
1import net.kromhouts.HqlBuilder
2import grails.orm.PagedResultList
3import org.hibernate.FetchMode as FM
4
5/**
6* Service class that encapsulates the business logic for Task searches.
7*/
8class TaskSearchService {
9
10    boolean transactional = false
11
12    def authService
13    def dateUtilService
14    def messageSource
15
16    def g = new org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib()
17
18    def paramsMax = 100000
19
20    // Be sure to update taskQuickSearchPane.js if quickSearchSelection is changed.
21    def getQuickSearchSelection() {
22        [ 'allTasks': g.message(code: 'task.search.text.all.tasks'),
23        'personsImmediateCallouts': g.message(code: 'task.search.text.persons.immediate.callouts'),
24        'personsTasks': g.message(code: 'task.search.text.persons.tasks')
25        ]
26    }
27
28    /**
29    * Selects and returns the correct search results based on the supplied quickSearch.
30    * @param params The request params, may contain params.quickSearch string to specify the search.
31    * @param locale The locale to use when generating result.message.
32    */
33    def getQuickSearch(params = [:], locale) {
34        def result = [:]
35        result.quickSearch = params.quickSearch ?: "personsTasks"
36        if(params.person)
37            result.person = Person.get(params.person.id.toLong())
38        else
39            result.person = authService.currentUser
40        result.startDate = params.startDate ?: dateUtilService.today
41        result.endDate = params.endDate ?: dateUtilService.today
42        // Auto swap date range.
43        if(result.startDate > result.endDate) {
44            def tempStartDate = result.startDate
45            result.startDate = result.endDate
46            result.endDate = tempStartDate
47        }
48        result.includeCompleted = params.includeCompleted = params.includeCompleted ? true:false
49
50        def getMessage = { Map m ->
51            messageSource.getMessage(m.code, m.args == null ? null : m.args.toArray(), locale)
52        }
53
54        def formatted = { Date d ->
55            g.formatDate(format: "EEE, dd-MMM-yyyy", date: d)
56        }
57
58        def startOfToday = dateUtilService.today
59        def startOfYesterday = dateUtilService.yesterday
60        def startOfTomorrow = dateUtilService.tomorrow
61        def oneWeekAgo = dateUtilService.oneWeekAgo
62
63        def formattedStartOfToday = formatted(startOfToday)
64        def formattedStartOfYesterday = formatted(startOfYesterday)
65        def formattedStartOfTomorrow = formatted(startOfTomorrow)
66        def formattedOneWeekAgo = formatted(oneWeekAgo)
67
68        def allTasks = {
69            result.taskInstanceList = getTasks(params, result.startDate, result.endDate+1)
70            if(result.taskInstanceList.totalCount > 0) {
71                if(result.startDate == result.endDate)
72                    result.message = getMessage(code:"task.search.text.all.tasks.message",
73                                                                    args:[ formatted(result.startDate) ])
74                else
75                    result.message = getMessage(code:"task.search.text.all.tasks.between.message",
76                                                                    args:[ formatted(result.startDate), formatted(result.endDate) ])
77            }
78            else {
79                if(result.startDate == result.endDate)
80                    result.message = getMessage(code:"task.search.text.all.tasks.none.found",
81                                                                    args:[ formatted(result.startDate) ])
82                else
83                    result.message = getMessage(code:"task.search.text.all.tasks.between.none.found",
84                                                                    args:[ formatted(result.startDate), formatted(result.endDate) ])
85            }
86
87        }
88
89        def personsTasks = {
90            result.taskInstanceList = getPersonsTasks(params, result.person, result.startDate, result.endDate+1)
91            if(result.taskInstanceList.totalCount > 0) {
92                if(result.startDate == result.endDate)
93                    result.message = getMessage(code:"task.search.text.persons.tasks.message",
94                                                                    args:[ result.person, formatted(result.startDate) ])
95                else
96                    result.message = getMessage(code:"task.search.text.persons.tasks.between.message",
97                                                                    args:[ result.person, formatted(result.startDate), formatted(result.endDate) ])
98            }
99            else {
100                if(result.startDate == result.endDate)
101                    result.message = getMessage(code:"task.search.text.persons.tasks.none.found",
102                                                                    args:[ result.person, formatted(result.startDate) ])
103                else
104                    result.message = getMessage(code:"task.search.text.persons.tasks.between.none.found",
105                                                                    args:[ result.person, formatted(result.startDate), formatted(result.endDate) ])
106            }
107
108        }
109
110        def personsImmediateCallouts = {
111            result.taskInstanceList = getPersonsImmediateCallouts(params, result.person, result.startDate, result.endDate+1)
112            if(result.taskInstanceList.totalCount > 0) {
113                if(result.startDate == result.endDate)
114                    result.message = getMessage(code:"task.search.text.persons.immediate.callouts.message",
115                                                                    args:[ result.person, formatted(result.startDate) ])
116                else
117                    result.message = getMessage(code:"task.search.text.persons.immediate.callouts.between.message",
118                                                                    args:[ result.person, formatted(result.startDate), formatted(result.endDate) ])
119            }
120            else {
121                if(result.startDate == result.endDate)
122                    result.message = getMessage(code:"task.search.text.persons.immediate.callouts.none.found",
123                                                                    args:[ result.person, formatted(result.startDate) ])
124                else
125                    result.message = getMessage(code:"task.search.text.persons.immediate.callouts.between.none.found",
126                                                                    args:[ result.person, formatted(result.startDate), formatted(result.endDate) ])
127            }
128
129        }
130
131        switch (result.quickSearch) {
132            case "myTodays":
133                result.quickSearch = "personsTasks"
134                result.startDate = startOfToday
135                result.endDate = startOfToday
136                personsTasks()
137                break
138            case "myYesterdays":
139                result.quickSearch = "personsTasks"
140                result.startDate = startOfYesterday
141                result.endDate = startOfYesterday
142                personsTasks()
143                break
144            case "myTomorrows":
145                result.quickSearch = "personsTasks"
146                result.startDate = startOfTomorrow
147                result.endDate = startOfTomorrow
148                personsTasks()
149                break
150            case "myPastWeek":
151                result.quickSearch = "personsTasks"
152                result.startDate = oneWeekAgo
153                result.endDate = startOfToday
154                personsTasks()
155                break
156            case "personsTasks":
157                personsTasks()
158                break
159            case "personsImmediateCallouts":
160                personsImmediateCallouts()
161                break
162            case "todays":
163                result.quickSearch = "allTasks"
164                result.startDate = startOfToday
165                result.endDate = startOfToday
166                allTasks()
167                break
168            case "yesterdays":
169                result.quickSearch = "allTasks"
170                result.startDate = startOfYesterday
171                result.endDate = startOfToday
172                allTasks()
173                break
174            case "tomorrows":
175                result.quickSearch = "allTasks"
176                result.startDate = startOfTomorrow
177                result.endDate = startOfTomorrow+1
178                allTasks()
179                break
180            case "pastWeek":
181                result.quickSearch = "allTasks"
182                result.startDate = oneWeekAgo
183                result.endDate = startOfTomorrow
184                allTasks()
185                break
186            case "allTasks":
187                allTasks()
188                break
189            default:
190                //case "plannersRange":
191                result.quickSearch = "allTasks"
192                result.startDate = oneWeekAgo
193                result.endDate = startOfToday+15
194                allTasks()
195                break
196        } // switch.
197
198        // Success.
199        return result
200
201    } // getQuickSearch
202
203    /**
204    * Get all tasks that are not in the trash bin, by default today's tasks.
205    * @param params The request params.
206    * @param startDate The start date to get tasks for, defaults to the start of today and is inclusive (greater than or equal to).
207    * @param endDate The end date to get tasks for, defaults to the start of tomorrow and is exclusive (less than).
208    */
209    def getTasks(params, startDate=null, endDate=null) {
210        def paginateParams = [:]
211        paginateParams.max = Math.min(params?.max?.toInteger() ?: 10, paramsMax)
212        paginateParams.offset = params?.offset?.toInteger() ?: 0
213
214        def orderBy = ''
215        if(params.sort?.contains('.')) // protect against filterpane bug.
216            params.sort = null
217        if(params.sort && params.order) {
218            def sort = "task." + params.sort
219            def order = (params.order == "asc") ? "asc" : "desc"
220            orderBy = " order by " + sort + ' ' + order
221        }
222        else
223            orderBy = " order by task.taskStatus, task.taskPriority, task.targetStartDate"
224
225        def namedParams = [:]
226        namedParams.startDate = startDate ?: dateUtilService.today
227        namedParams.endDate = endDate ?: dateUtilService.tomorrow
228
229        def baseQuery = "from Task as task \
230                                        where (task.trash = false \
231                                                    and task.targetStartDate < :endDate \
232                                                    and task.targetCompletionDate >= :startDate \
233                                        )"
234
235        def searchQuery = "select distinct task " + baseQuery + orderBy
236        def list = Task.executeQuery(searchQuery, namedParams, paginateParams)
237
238        def countQuery = "select count(distinct task) as taskCount " + baseQuery
239        def totalCount = Task.executeQuery(countQuery, namedParams)[0].toInteger()
240
241        def taskInstanceList = new PagedResultList(list, totalCount)
242        return taskInstanceList
243    } // getTasks()
244
245    /**
246    * Get a person's tasks, by default current user and today's tasks.
247    * "My tasks and approved tasks that I am assigned to"
248    * @param params The request params.
249    * @param person The person to get tasks for, defaults to current user.
250    * @param startDate The start date to get tasks for, defaults to the start of today and is inclusive (greater than or equal to).
251    * @param endDate The end date to get tasks for, defaults to the start of tomorrow and is exclusive (less than).
252    */
253    def getPersonsTasks(params, person=null, startDate=null, endDate=null) {
254
255        def max = Math.min(params?.max?.toInteger() ?: 10, paramsMax)
256        def offset = params?.offset?.toInteger() ?: 0
257
258        def orderBy = ''
259        if(params.sort?.contains('.')) // protect against filterpane bug.
260            params.sort = null
261        if(params.sort && params.order) {
262            def sort = "task." + params.sort
263            def order = (params.order == "asc") ? "asc" : "desc"
264            orderBy = "by " + sort + ' ' + order
265        }
266        else
267            orderBy = "by task.taskPriority, task.targetStartDate, task.taskStatus"
268
269        def q = new HqlBuilder().query {
270
271            select 'count(distinct task) as taskCount'
272            from 'Task as task',
273                    'left join task.assignedPersons as assignedPersonOfTask',
274                    'left join assignedPersonOfTask.person as assignedPerson',
275                    'left join task.assignedGroups as assignedGroupOfTask',
276                    'left join assignedGroupOfTask.personGroup as personGroup',
277                    'left join personGroup.persons as assignedPersonViaGroup',
278                    'left join task.taskModifications as taskModification',
279                    'left join taskModification.person as createdBy',
280                    'left join taskModification.taskModificationType as taskModificationType'
281            where 'task.trash = false'
282                    and 'task.targetStartDate < :endDate'
283                    and 'task.targetCompletionDate >= :startDate'
284                    if(!params.includeCompleted) {
285                        and 'task.taskStatus.id != 3' // Complete.
286                    }
287                    and {
288                        where '(taskModificationType.id = 1 and createdBy = :person and task.leadPerson = :person)' // Created.
289                        or '(task.approved = true and (task.leadPerson = :person or assignedPerson = :person or assignedPersonViaGroup = :person))'
290                    }
291        }
292
293        q.namedParams.person = person ?: authService.currentUser
294        q.namedParams.startDate = startDate ?: dateUtilService.today
295        q.namedParams.endDate = endDate ?: dateUtilService.tomorrow
296
297        def totalCount = Task.executeQuery(q.query, q.namedParams)[0].toInteger()
298
299        q.select = "distinct task"
300        q.order = orderBy
301        q.paginateParams.max = max
302        q.paginateParams.offset = offset
303        def list = Task.executeQuery(q.query, q.namedParams, q.paginateParams)
304
305        def taskInstanceList = new PagedResultList(list, totalCount)
306        return taskInstanceList
307    } // getPersonsTasks()
308
309    /**
310    * Get a person's immediateCallout tasks, by default all users and today's tasks.
311    * @param params The request params.
312    * @param person The person to get tasks for, defaults to null and therefore all immediateCallouts.
313    * @param startDate The start date to get tasks for, defaults to the start of today and is inclusive (greater than or equal to).
314    * @param endDate The end date to get tasks for, defaults to the start of tomorrow and is exclusive (less than).
315    */
316    def getPersonsImmediateCallouts(params, person=null, startDate=null, endDate=null) {
317
318        def max = Math.min(params?.max?.toInteger() ?: 10, paramsMax)
319        def offset = params?.offset?.toInteger() ?: 0
320
321        def orderBy = ''
322        if(params.sort?.contains('.')) // protect against filterpane bug.
323            params.sort = null
324        if(params.sort && params.order) {
325            def sort = "task." + params.sort
326            def order = (params.order == "asc") ? "asc" : "desc"
327            orderBy = "by " + sort + ' ' + order
328        }
329        else
330            orderBy = "by task.taskStatus, task.targetStartDate"
331
332        def q = new HqlBuilder().query {
333
334            select 'count(distinct task) as taskCount'
335            from 'Task as task',
336                    'left join task.taskModifications as taskModification',
337                    'left join taskModification.person as createdBy',
338                    'left join taskModification.taskModificationType as taskModificationType'
339            where 'task.taskType.id = 1' // Immediate Callout.
340                    and 'task.targetStartDate < :endDate'
341                    and 'task.targetCompletionDate >= :startDate'
342                    if(!params.includeCompleted) {
343                        and 'task.taskStatus.id != 3' // Complete.
344                    }
345                    if(person) {
346                        namedParams.person = person
347                        and '( (taskModificationType.id = 1 and createdBy = :person) or task.leadPerson = :person)' // Created or Lead Person.
348                    }
349                    and 'task.trash = false'
350        }
351
352        q.namedParams.startDate = startDate ?: dateUtilService.today
353        q.namedParams.endDate = endDate ?: dateUtilService.tomorrow
354
355        def totalCount = Task.executeQuery(q.query, q.namedParams)[0].toInteger()
356
357        q.select = "distinct task"
358        q.order = orderBy
359        q.paginateParams.max = max
360        q.paginateParams.offset = offset
361        def list = Task.executeQuery(q.query, q.namedParams, q.paginateParams)
362
363        def taskInstanceList = new PagedResultList(list, totalCount)
364        return taskInstanceList
365    } // getPersonsImmediateCallouts()
366
367    /**
368    * Get work done by person and date.
369    * A person ID and date may be specified in params otherwise the current user and today are used.
370    * @param params The request params.
371    * @returns A map containing entries, totalEntries, startOfDay, person, totalHours, totalMinutes.
372    */
373    def getWorkDone(params, locale) {
374        def result = [:]
375        result.person = params.person?.id ? Person.get(params.person.id.toInteger()) : authService.currentUser
376
377        if(params.date_year && params.date_month && params.date_day)
378            result.startOfDay = dateUtilService.makeDate(params.date_year, params.date_month, params.date_day)
379        else
380            result.startOfDay = dateUtilService.today
381
382        result.startOfNextDay = result.startOfDay + 1
383
384        def formattedStartOfDay = g.formatDate(format: "EEE, dd-MMM-yyyy", date: result.startOfDay)
385
386        def getMessage = { Map m ->
387            messageSource.getMessage(m.code, m.args == null ? null : m.args.toArray(), locale)
388        }
389
390        result.entries = Entry.createCriteria().list() {
391            eq("enteredBy", result.person)
392            ge("dateDone", result.startOfDay)
393            lt("dateDone", result.startOfNextDay)
394            entryType {
395                or {
396                    idEq(3L) // Work Done.
397                    idEq(6L) // PM Entry.
398                }
399            }
400        } // createCriteria
401
402        result.totalEntries = result.entries.size()
403
404        if(result.totalEntries > 0)
405            result.message = getMessage(code:"task.search.text.work.done.message",
406                                                                args:[result.person, formattedStartOfDay])
407        else
408            result.message = getMessage(code:"task.search.text.work.done.none.found",
409                                                                args:[result.person, formattedStartOfDay])
410
411        result.totalHours = 0
412        result.totalMinutes = 0
413        result.entries.each() {
414            result.totalMinutes += (it.durationHour*60) + it.durationMinute
415        }
416        result.totalHours = (result.totalMinutes / 60).toInteger()
417        result.totalMinutes = result.totalMinutes % 60
418
419        return result
420    } // getWorkDone()
421
422    /**
423    * Get work load by task group and date.
424    * Group ID's and date range may be specified in params otherwise no group and today are used.
425    * @param params The request params.
426    * @returns A map containing the results.
427    */
428    def getWorkLoad(params, locale) {
429        def result = [:]
430        def max = 1000
431
432        // TaskStatus..
433        result.taskStatusList = []
434        if(params.taskStatusList instanceof String)
435            result.taskStatusList << TaskStatus.get(params.taskStatusList.toInteger())
436        else if(params.taskStatusList)
437            result.taskStatusList = TaskStatus.getAll( params.taskStatusList.collect {it.toInteger()} )
438
439        // TaskGroups.
440        result.taskGroups = []
441        if(params.taskGroups instanceof String)
442            result.taskGroups << TaskGroup.get(params.taskGroups.toInteger())
443        else if(params.taskGroups)
444            result.taskGroups = TaskGroup.getAll( params.taskGroups.collect {it.toInteger()} )
445
446        // Start Date.
447        if(params.startDate_year && params.startDate_month && params.startDate_day)
448            result.startDate = dateUtilService.makeDate(params.startDate_year, params.startDate_month, params.startDate_day)
449        else
450            result.startDate = dateUtilService.today
451
452        // End Date.
453        if(params.endDate_year && params.endDate_month && params.endDate_day)
454            result.endDate = dateUtilService.makeDate(params.endDate_year, params.endDate_month, params.endDate_day)
455        else
456            result.endDate = result.startDate
457
458        // Auto swap date range.
459        if(result.startDate > result.endDate) {
460            def tempStartDate = result.startDate
461            result.startDate = result.endDate
462            result.endDate = tempStartDate
463        }
464
465        def formattedStartDate = g.formatDate(format: "EEE, dd-MMM-yyyy", date: result.startDate)
466        def formattedEndDate = g.formatDate(format: "EEE, dd-MMM-yyyy", date: result.endDate)
467
468        def getMessage = { Map m ->
469            messageSource.getMessage(m.code, m.args == null ? null : m.args.toArray(), locale)
470        }
471
472        result.tasks = new PagedResultList([], 0)
473
474        if(result.taskGroups && result.taskStatusList) {
475
476            result.tasks = Task.createCriteria().list(max: max) {
477                eq("trash", false)
478                lt("targetStartDate", result.endDate+1)
479                ge("targetCompletionDate", result.startDate)
480                inList("taskStatus", result.taskStatusList)
481                inList("taskGroup", result.taskGroups)
482                order("taskStatus", "asc")
483                order("taskPriority", "asc")
484                order("targetStartDate", "asc")
485                fetchMode("assignedGroups", FM.EAGER)
486                fetchMode("assignedGroups.personGroup", FM.EAGER)
487            } // createCriteria
488
489        }
490
491        result.tasks.list.unique()
492        result.totalHours = 0
493        result.totalMinutes = 0
494        result.workLoadGroups = [:]
495
496        // Exit early!
497        if(result.tasks.totalCount > result.tasks.size()) {
498            result.errorMessage = getMessage(code:"task.search.text.work.load.too.many.results",
499                                                                args:[result.tasks.size(), result.tasks.totalCount])
500            return result
501        }
502        else if(result.tasks.size() > 0)
503            result.message = getMessage(code:"task.search.text.work.load.message",
504                                                                args:[formattedStartDate, formattedEndDate])
505        else
506            result.message = getMessage(code:"task.search.text.work.load.none.found",
507                                                                args:[formattedStartDate, formattedEndDate])
508
509        // Collect all assignedGroups.
510        def assignedGroups = []
511        for(task in result.tasks) {
512            for(assignedGroup in task.assignedGroups) {
513                assignedGroups << assignedGroup
514            }
515        }
516
517        // Calculate work load for each personGroup and minute totals.
518        def tempHours = 0
519        def tempMinutes = 0
520        def personGroup
521        for(assignedGroup in assignedGroups) {
522            personGroup = assignedGroup.personGroup
523            if(!result.workLoadGroups.containsKey(personGroup)) {
524                result.workLoadGroups[personGroup] = [hours: 0, minutes: 0]
525            }
526
527            tempMinutes = (assignedGroup.estimatedHour*60) + assignedGroup.estimatedMinute
528            result.totalMinutes += tempMinutes
529            result.workLoadGroups[personGroup].minutes += tempMinutes
530        }
531
532        // Resolve totals and sort.
533        result.workLoadGroups.each { workLoadGroup ->
534            workLoadGroup.value.hours =  (workLoadGroup.value.minutes / 60).toInteger()
535            workLoadGroup.value.minutes = workLoadGroup.value.minutes % 60
536        }
537        result.workLoadGroups = result.workLoadGroups.sort { p1, p2 -> p1.key.name.compareToIgnoreCase(p2.key.name) }
538        result.totalHours = (result.totalMinutes / 60).toInteger()
539        result.totalMinutes = result.totalMinutes % 60
540
541        // Success.
542        return result
543    } // getWorkLoad()
544
545} // end class
Note: See TracBrowser for help on using the repository browser.