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

Last change on this file since 701 was 701, checked in by gav, 13 years ago

New workLoad search view and logic to suite.

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