source: trunk/grails-app/services/AssetReportService.groovy @ 732

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

Auto swap date range in all reports.

File size: 13.1 KB
Line 
1import net.kromhouts.HqlBuilder
2
3/**
4* Service class that encapsulates the business logic for Asset Reports.
5*/
6class AssetReportService {
7
8    boolean transactional = false
9
10    def authService
11    def dateUtilService
12//     def messageSource
13
14    def g = new org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib()
15
16    def paramsMax = 100000
17
18    /**
19    * Selects and returns the assets and their details.
20    * @param params The request params, may contain params to specify the search.
21    * @param locale The locale to use when generating result.message.
22    */
23    def getAssetRegister(params, locale) {
24        def result = [:]
25
26        result.section = Section.get(params.section.id.toLong())
27        result.site = result.section.site
28
29        // Inner join used to return only attribTypes that are used by AssetExtendedAttributes.
30        // So the result is only asset extendedAttributeTypes.
31//         def attribTypesQ = new HqlBuilder().query {
32//             select 'distinct attribT.name'
33//             from 'AssetExtendedAttribute attrib',
34//                     'join attrib.extendedAttributeType as attribT'
35//             order 'by attribT.name asc'
36//         }
37
38        // All active ExtendedAttributes.
39        def attribTypesQ = new HqlBuilder().query {
40            select 'distinct attribT.name'
41            from 'ExtendedAttributeType attribT'
42            where 'attribT.isActive = true'
43            order 'by attribT.name asc'
44        }
45        result.attribTypes = ExtendedAttributeType.executeQuery(attribTypesQ.query, attribTypesQ.namedParams)
46
47        // A result is returned for every asset and for any extended attributes.
48        def q = new HqlBuilder().query {
49            select 'new map(asset.name as name',
50                        'asset.description as description',
51                        'asset.comment as comment',
52                        'attribT.name as attribType',
53                        'attrib.value as attribValue)'
54            from 'Asset asset',
55                    'left join asset.assetExtendedAttributes as attrib',
56                    'left join attrib.extendedAttributeType as attribT'
57            where 'asset.section = :section'
58                    namedParams.section = result.section
59            order 'by asset.name asc, attribT.name asc'
60        }
61        def assetResults = Asset.executeQuery(q.query, q.namedParams)
62
63        // Build the report table row for each asset.
64        // Rows are keyed by asset.name and the value is a Map of the attributes.
65        def rows = [:]
66        assetResults.each { assetResult ->
67            // Create row if it does not exist yet.
68            if(!rows.containsKey(assetResult.name)) {
69                rows[assetResult.name] = ['name':assetResult.name,
70                                                            'description':assetResult.description,
71                                                            'comment':assetResult.comment]
72
73                // Add all attribType columns.
74                result.attribTypes.each { column ->
75                    rows[assetResult.name][column] = ' '
76                }
77            }
78
79            // Assign value to column.
80            rows[assetResult.name][assetResult.attribType] = assetResult.attribValue
81        }
82
83        // The value of each row is the dataList used by the report table.
84        result.dataList = rows.collect {it.value}
85
86        // Success.
87        return result
88
89    } // getAssetRegister
90
91    /**
92    * Selects and returns an asset (or all) and its details.
93    * @param params The request params, may contain params to specify the search.
94    * @param locale The locale to use when generating result.message.
95    */
96    def getAssetDetail(params, locale) {
97        //def result = [:]
98        def result
99
100        //result.summaryOfCalculationMethod = ''
101
102        // A result is returned for every asset and for any extended attributes.
103        // The report then groups by asset.name
104        def q = new HqlBuilder().query {
105            select 'new map(asset.name as name',
106                        'asset.description as description',
107                        'asset.comment as comment',
108                        'attribT.name as attribType',
109                        'attrib.value as attribValue)'
110            from 'Asset asset',
111                    'left join asset.assetExtendedAttributes as attrib',
112                    'left join attrib.extendedAttributeType as attribT'
113            if(params.section instanceof Section) {
114                namedParams.section = params.section
115                where 'asset.section = :section'
116            }
117            order 'by asset.name asc, attribT.name asc'
118        }
119
120        // result.dataList = Asset.list()
121        result = Asset.executeQuery(q.query, q.namedParams)
122
123        // Success.
124        return result
125
126    } // getAssetDetail
127
128    /**
129    * Selects and returns level 1 sub items (aka machines or equipment) and their details.
130    * @param params The request params, may contain params to specify the search.
131    * @param locale The locale to use when generating result.message.
132    */
133    def getEquipmentRegister(params, locale) {
134        def result = [:]
135
136        def fail = { Map m ->
137            result.error = [ code: m.code, args: [] ]
138            return result
139        }
140
141        result.section = Section.get(params.section.id.toLong())
142        result.site = result.section.site
143
144        // Start date.
145        if(params.startDate)
146            params.startDate = dateUtilService.makeDate(params.startDate_year, params.startDate_month, params.startDate_day)
147        else
148            params.startDate = dateUtilService.oneWeekAgo
149
150        // End date.
151        if(params.endDate)
152            params.endDate = dateUtilService.makeDate(params.endDate_year, params.endDate_month, params.endDate_day)
153        else
154            params.endDate = dateUtilService.today
155
156        // Auto swap date range.
157        if(params.startDate > params.endDate) {
158            def tempStartDate = params.startDate
159            params.startDate = params.endDate
160            params.endDate = tempStartDate
161        }
162
163        // Inner join used to return only attribTypes that are used by AssetSubItemExtendedAttributes.
164        // So the result is only assetSubItem extendedAttributeTypes.
165//         def attribTypesQ = new HqlBuilder().query {
166//             select 'distinct attribT.name'
167//             from 'AssetSubItemExtendedAttribute attrib',
168//                     'join attrib.extendedAttributeType as attribT'
169//             order 'by attribT.name asc'
170//         }
171
172        // All active ExtendedAttributes.
173        def attribTypesQ = new HqlBuilder().query {
174            select 'distinct attribT.name'
175            from 'ExtendedAttributeType attribT'
176            where 'attribT.isActive = true'
177            order 'by attribT.name asc'
178        }
179        result.attribTypes = ExtendedAttributeType.executeQuery(attribTypesQ.query, attribTypesQ.namedParams)
180
181        // A useful list of assets without subItems to be given to the user.
182        def assetsWithoutEquipmentQ = new HqlBuilder().query {
183            select 'distinct asset'
184            from 'Asset asset',
185                    'left join asset.assetSubItems as assetSubItem'
186            where 'assetSubItem = null'
187                namedParams.section = result.section
188                and 'asset.section = :section'
189        }
190        result.assetsWithoutEquipment = AssetSubItem.executeQuery(assetsWithoutEquipmentQ.query, assetsWithoutEquipmentQ.namedParams)
191
192        // Subquery to count regulatory tasks.
193        def regulatoryTaskCountQ = new HqlBuilder().query {
194
195            select 'count (distinct task)'
196            from 'Task as task',
197                    'left join task.associatedAssets as associatedAsset'
198            where 'task.regulatoryRequirement = true'
199                and 'task.targetStartDate < :endDate'
200                and 'task.targetCompletionDate >= :startDate'
201                and '(task.primaryAsset.id = asset.id or associatedAsset.id = asset.id)'
202                and 'task.trash = false'
203        }
204
205        def totalRegulatoryTaskCountQ = regulatoryTaskCountQ.query
206
207        regulatoryTaskCountQ.and 'task.taskStatus.id = 3'
208        def completedRegulatoryTaskCountQ = regulatoryTaskCountQ.query
209
210        // A result is returned for every level 1 assetSubItem and for any extended attributes.
211        def q = new HqlBuilder().query {
212
213            select 'new map(asset.name as assetName',
214                        'assetSubItem.name as name',
215                        'assetSubItem.description as description',
216                        'assetSubItem.comment as comment',
217                        "0 as totalRegulatoryTaskCount",
218                        "0 as completedRegulatoryTaskCount",
219                        'attribT.name as attribType',
220                        'attrib.value as attribValue)'
221            from 'AssetSubItem assetSubItem',
222                    'inner join assetSubItem.assets as asset',
223                    'left join assetSubItem.assetSubItemExtendedAttributes as attrib',
224                    'left join attrib.extendedAttributeType as attribT'
225            where 'asset != null' // ensure that only level 1 assetSubItems are returned.
226                namedParams.section = result.section
227                and 'asset.section = :section'
228            order 'by asset.name asc, assetSubItem.name asc, attribT.name asc'
229        }
230        def equipmentResults = AssetSubItem.executeQuery(q.query, q.namedParams)
231
232        // A result is returned for every asset and for any extended attributes.
233        def assetResultsQ = new HqlBuilder().query {
234
235            // Subquery namedParams.
236            namedParams.startDate = params.startDate
237            namedParams.endDate = params.endDate+1
238
239            select 'new map(asset.name as assetName',
240                        "'   Asset Details' as name", // Place holder 'equipment' name, 3 leading spaces for sorting.
241                        'asset.description as description',
242                        'asset.comment as comment',
243                        "($totalRegulatoryTaskCountQ) as totalRegulatoryTaskCount",
244                        "($completedRegulatoryTaskCountQ) as completedRegulatoryTaskCount",
245                        'attribT.name as attribType',
246                        'attrib.value as attribValue)'
247            from 'Asset asset',
248                    'left join asset.assetExtendedAttributes as attrib',
249                    'left join attrib.extendedAttributeType as attribT'
250            where 'asset.section = :section'
251                    namedParams.section = result.section
252            order 'by asset.name asc, attribT.name asc'
253        }
254        def assetResults = Asset.executeQuery(assetResultsQ.query, assetResultsQ.namedParams)
255
256        // Add asset details to equipmentResults.
257        equipmentResults.addAll(assetResults)
258        equipmentResults.sort { p1, p2 -> p1.assetName.compareToIgnoreCase(p2.assetName) ?: p1.name.compareToIgnoreCase(p2.name) }
259
260        // Build the report table rows.
261        // Rows are keyed by equipmentResult.assetName+equipmentResult.name` while the value is a Map of the attributes.
262        // The report table then groups by assetName.
263        def rows = [:]
264        equipmentResults.each { equipmentResult ->
265
266            def rowKey = equipmentResult.assetName+equipmentResult.name
267
268            // Create new row if it does not exist yet.
269            if(!rows.containsKey(rowKey)) {
270                rows[rowKey] = ['assetName': equipmentResult.assetName,
271                                            'name':equipmentResult.name,
272                                            'description':equipmentResult.description,
273                                            'comment':equipmentResult.comment,
274                                            'Regulatory Task Completion': ' ']
275
276                // Add all attribType columns.
277                result.attribTypes.each { column ->
278                    rows[rowKey][column] = ' '
279                }
280
281                // Caluculate and assign RegulatoryTaskCompletion, only for Assets.
282                if(params.calculateRegulatoryTaskCompletion) {
283
284                    if(equipmentResult.totalRegulatoryTaskCount) {
285                        def percentComplete = (equipmentResult.completedRegulatoryTaskCount / equipmentResult.totalRegulatoryTaskCount)*100
286                        rows[rowKey]['Regulatory Task Completion'] = "${percentComplete.toInteger()}% (${equipmentResult.completedRegulatoryTaskCount}/${equipmentResult.totalRegulatoryTaskCount})"
287                    }
288                    else if(equipmentResult.name == '   Asset Details')
289                        rows[rowKey]['Regulatory Task Completion'] = 'N/A'
290                }
291
292            } // Create new row.
293
294            // Assign value to column.
295            rows[rowKey][equipmentResult.attribType] = equipmentResult.attribValue
296        } // each.
297
298        // The value of each row is the dataList used by the report table.
299        result.dataList = rows.collect {it.value}
300        // Print formatting, since we are done with these as objects.
301        result.attribTypes = result.attribTypes.join(', ')
302        result.assetsWithoutEquipment = result.assetsWithoutEquipment.collect {it.name}.join(', ')
303
304        // Success.
305        return result
306
307    } // getEquipmentRegister
308
309} // end class
Note: See TracBrowser for help on using the repository browser.