source: trunk/grails-app/controllers/InventoryItemDetailedController.groovy @ 615

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

Fix NPE during pagination after setSearchParamsMax in search views.

File size: 22.0 KB
Line 
1import org.codehaus.groovy.grails.plugins.springsecurity.Secured
2import org.codehaus.groovy.grails.commons.ConfigurationHolder
3import com.zeddware.grails.plugins.filterpane.FilterUtils
4import org.springframework.web.servlet.support.RequestContextUtils as RCU
5
6@Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager'])
7class InventoryItemDetailedController extends BaseController {
8
9    def filterService
10    def exportService
11    def inventoryCsvService
12    def inventoryItemService
13    def inventoryItemSearchService
14    def inventoryMovementService
15
16    // the delete, save and update actions only accept POST requests
17    static allowedMethods = [delete:'POST', save:'POST', update:'POST', useInventoryItem:'POST']
18
19    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
20    def index = { redirect(action:search, params:params) }
21
22    /**
23    * Set session.inventoryItemSearchParamsMax
24    */
25    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
26    def setSearchParamsMax = {
27        def max = 1000
28        if(params.newMax?.isInteger()) {
29            def i = params.newMax.toInteger()
30            if(i > 0 && i <= max)
31                session.inventoryItemSearchParamsMax = params.newMax
32            if(i > max)
33                session.inventoryItemSearchParamsMax = max
34        }
35        forward(action: 'search', params: params)
36    }
37
38    /**
39    * Display the import view.
40    */
41    def importInventory = {
42    }
43
44    /**
45    * Handle the import save.
46    */
47    def importInventorySave = {
48        def result = inventoryCsvService.importInventory(request)
49
50        if(!result.error) {
51            flash.message = g.message(code: "inventory.import.success")
52            redirect(action:search)
53            return
54        }
55
56        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
57        redirect(action: importInventory)
58    }
59
60    /**
61    * Export a csv template.
62    * NOTE: IE has a 'validating' bug in dev mode that causes the export to take a long time!
63    * This does not appear to be a problem once deployed to Tomcat.
64    */
65    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
66    def exportInventoryTemplate = {
67        response.contentType = ConfigurationHolder.config.grails.mime.types["csv"]
68        response.setHeader("Content-disposition", "attachment; filename=InventoryTemplate.csv")
69        def s = inventoryCsvService.buildInventoryTemplate()
70        render s
71    }
72
73    /**
74    * Export a csv test file.
75    */
76    def exportInventoryExample = {
77        response.contentType = ConfigurationHolder.config.grails.mime.types["csv"]
78        response.setHeader("Content-disposition", "attachment; filename=InventoryExample.csv")
79        def s = inventoryCsvService.buildInventoryExample()
80        render s
81    }
82
83    /**
84    * Export the entire inventory as a csv file.
85    */
86    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
87    def exportInventory = {
88
89        def inventoryItemList = InventoryItem.list()
90
91        response.contentType = ConfigurationHolder.config.grails.mime.types["csv"]
92        response.setHeader("Content-disposition", "attachment; filename=Inventory.csv")
93        def s = inventoryCsvService.buildInventory(inventoryItemList)
94        render s
95    }
96
97    /**
98    * Display the import view for purchases.
99    */
100    def importInventoryItemPurchases = {
101    }
102
103    /**
104    * Handle the inventory purchases import save.
105    */
106    def importInventoryItemPurchasesSave = {
107        def result = inventoryCsvService.importInventoryItemPurchases(request)
108
109        if(!result.error) {
110            flash.message = g.message(code: "inventory.import.success")
111            redirect(action:search)
112            return
113        }
114
115        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
116        redirect(action: importInventoryItemPurchases)
117    }
118
119    /**
120    * Search for Inventory items.
121    */
122    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
123    def search = {
124
125        if(session.inventoryItemSearchParamsMax)
126            params.max = session.inventoryItemSearchParamsMax
127
128        // Protect filterPane.
129        params.max = Math.min( params.max ? params.max.toInteger() : 10,  1000)
130
131        def inventoryItemInstanceList = []
132        def inventoryItemInstanceTotal
133        def filterParams = com.zeddware.grails.plugins.filterpane.FilterUtils.extractFilterParams(params)
134        def isFilterApplied = FilterUtils.isFilterApplied(params)
135
136        // Restore default sort if a new text search is requested
137        if(params.newTextSearch) {
138            params.sort = 'id'
139            params.order = 'desc'
140        }
141
142        // Restore search unless a new search is being requested.
143        if(!params.searchText && !params.quickSearch && !filterParams) {
144            if(session.inventoryItemSearchText) {
145                params.searchText = session.inventoryItemSearchText
146                params.searchName = session.inventoryItemSearchName
147                params.searchDescription = session.inventoryItemSearchDescription
148                params.searchComment = session.inventoryItemSearchComment
149                params.searchLocation = session.inventoryItemSearchLocation
150                params.searchGroup = session.inventoryItemSearchGroup
151                params.searchSpareFor = session.inventoryItemSearchSpareFor
152            }
153            else if(session.inventoryItemQuickSearch) {
154                params.quickSearch = session.inventoryItemQuickSearch
155                if(session.inventoryItemQuickSearchDaysBack)
156                    params.daysBack = session.inventoryItemQuickSearchDaysBack.toString()
157            }
158            else if(session.inventoryItemSearchFilterParams) {
159                session.inventoryItemSearchFilterParams.each() { params[it.key] = it.value }
160                params.filter = session.inventoryItemSearchFilter
161                isFilterApplied = FilterUtils.isFilterApplied(params)
162            }
163        }
164
165        // Remember sort if supplied, otherwise try to restore.
166        if(params.sort && params.order) {
167             session.inventoryItemSearchSort = params.sort
168             session.inventoryItemSearchOrder = params.order
169        }
170        else if(session.inventoryItemSearchSort && session.inventoryItemSearchOrder) {
171            params.sort = session.inventoryItemSearchSort
172            params.order = session.inventoryItemSearchOrder
173        }
174
175        if(isFilterApplied) {
176            // filterPane:
177            inventoryItemInstanceList = filterService.filter( params, InventoryItem )
178            inventoryItemInstanceTotal = filterService.count( params, InventoryItem )
179            filterParams = com.zeddware.grails.plugins.filterpane.FilterUtils.extractFilterParams(params)
180            // Remember search.
181            session.inventoryItemSearchFilterParams = new LinkedHashMap(filterParams)
182            session.inventoryItemSearchFilter = new LinkedHashMap(params.filter)
183            // Clear any previous search.
184            session.removeAttribute("inventoryItemSearchText")
185            session.removeAttribute("inventoryItemSearchName")
186            session.removeAttribute("inventoryItemSearchDescription")
187            session.removeAttribute("inventoryItemSearchComment")
188            session.removeAttribute("inventoryItemSearchLocation")
189            session.removeAttribute("inventoryItemSearchGroup")
190            session.removeAttribute("inventoryItemSearchSpareFor")
191            session.removeAttribute("inventoryItemQuickSearch")
192            session.removeAttribute("inventoryItemQuickSearchDaysBack")
193        }
194        else if(params.searchText) {
195            // Quick Search Text:
196            def result = inventoryItemSearchService.getTextSearch(params, RCU.getLocale(request))
197            inventoryItemInstanceList = result.inventoryItemList
198            inventoryItemInstanceTotal = result.inventoryItemList.totalCount
199            params.message = result.message
200            filterParams.searchText = result.searchText
201            // Remember search.
202            session.inventoryItemSearchText = params.searchText
203            session.inventoryItemSearchName = params.searchName
204            session.inventoryItemSearchDescription = params.searchDescription
205            session.inventoryItemSearchComment = params.searchComment
206            session.inventoryItemSearchLocation = params.searchLocation
207            session.inventoryItemSearchGroup = params.searchGroup
208            session.inventoryItemSearchSpareFor = params.searchSpareFor
209            // Clear any previous search.
210            session.removeAttribute("inventoryItemQuickSearch")
211            session.removeAttribute("inventoryItemQuickSearchDaysBack")
212            session.removeAttribute("inventoryItemSearchFilterParams")
213            session.removeAttribute("inventoryItemSearchFilter")
214        }
215        else {
216            // Quick Search Links:
217            if(!params.quickSearch) params.quickSearch = "all"
218            def result = inventoryItemSearchService.getQuickSearch(params, RCU.getLocale(request))
219            inventoryItemInstanceList = result.inventoryItemList
220            inventoryItemInstanceTotal = result.inventoryItemList.totalCount
221            params.message = result.message
222            filterParams.quickSearch = result.quickSearch
223            // Remember search.
224            session.inventoryItemQuickSearch = result.quickSearch
225            if(result.daysBack)
226                session.inventoryItemQuickSearchDaysBack = result.daysBack
227            // Clear any previous search.
228            session.removeAttribute("inventoryItemSearchText")
229            session.removeAttribute("inventoryItemSearchName")
230            session.removeAttribute("inventoryItemSearchDescription")
231            session.removeAttribute("inventoryItemSearchComment")
232            session.removeAttribute("inventoryItemSearchLocation")
233            session.removeAttribute("inventoryItemSearchGroup")
234            session.removeAttribute("inventoryItemSearchSpareFor")
235            session.removeAttribute("inventoryItemSearchFilterParams")
236            session.removeAttribute("inventoryItemSearchFilter")
237        }
238
239        // export plugin:
240        if(params?.format && params.format != "html") {
241
242            def dateFmt = { date ->
243                formatDate(format: "EEE, dd-MMM-yyyy", date: date)
244            }
245
246            String title
247            if(params.quickSearch)
248                title = params.message
249            else
250                title = "Filtered Inventory List."
251
252            response.contentType = ConfigurationHolder.config.grails.mime.types[params.format]
253            response.setHeader("Content-disposition", "attachment; filename=Inventory.${params.extension}")
254            List fields = ["name",
255                                "description",
256                                "inventoryGroup",
257                                "unitsInStock",
258                                "reorderPoint",
259                                "unitOfMeasure",
260                                "inventoryLocation",
261                                "inventoryLocation.inventoryStore"]
262            Map labels = ["name": "Name",
263                                "description": "Description",
264                                "inventoryGroup": "Group",
265                                "unitsInStock":"In Stock",
266                                "reorderPoint":"Reorder Point",
267                                "unitOfMeasure": "UOM",
268                                "inventoryLocation": "Location",
269                                "inventoryLocation.inventoryStore": "Store"]
270
271            Map formatters = [:]
272            Map parameters = [title: title, separator: ","]
273
274            exportService.export(params.format,
275                                                response.outputStream,
276                                                inventoryItemInstanceList.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) },
277                                                fields,
278                                                labels,
279                                                formatters,
280                                                parameters)
281        }
282
283        // Add some basic params to filterParams.
284        filterParams.max = params.max
285        filterParams.offset = params.offset?.toInteger() ?: 0
286        filterParams.sort = params.sort ?: "name"
287        filterParams.order = params.order ?: "asc"
288
289        // Get some associatedProperty values for filterpane.
290        def associatedPropertyValues = [:]
291        def associatedPropertyMax = 10000
292        associatedPropertyValues.inventoryLocationList = InventoryLocation.findAllByIsActive(true, [max:associatedPropertyMax, sort:'name'])
293        associatedPropertyValues.assetList = Asset.findAllByIsActive(true, [max:associatedPropertyMax, sort:'name'])
294        associatedPropertyValues.manufacturerList = Manufacturer.findAllByIsActive(true, [max:associatedPropertyMax, sort:'name'])
295        associatedPropertyValues.supplierList = Supplier.findAllByIsActive(true, [max:associatedPropertyMax, sort:'name'])
296
297        return[ inventoryItemInstanceList: inventoryItemInstanceList,
298                        inventoryItemInstanceTotal: inventoryItemInstanceTotal,
299                        filterParams: filterParams,
300                        params: params,
301                        associatedPropertyValues: associatedPropertyValues ]
302    } // end search()
303
304    /**
305    * Simply assigns a passed in task id to a session variable and redirects to search.
306    */
307    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
308    def findInventoryItemForMovement = {
309        if(!params.task?.id) {
310            flash.message = "No task id supplied, please select a task then the inventory tab."
311            redirect(controller: "taskDetailed", action: "search")
312            return
313        }
314
315        session.inventoryMovementTaskId = params.task.id
316        flash.message = "Please find and then select the inventory item."
317        redirect(action: search)
318    }
319
320    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
321    def show = {
322
323        // In the case of an actionSubmit button, rewrite action name from 'index'.
324        if(params._action_Show)
325            params.action='show'
326
327        def result = inventoryItemService.show(params)
328
329        if(!result.error) {
330
331            def model = [ inventoryItemInstance: result.inventoryItemInstance,
332                                    inventoryMovementList: result.inventoryMovementList,
333                                    inventoryMovementListTotal: result.inventoryMovementListTotal,
334                                    inventoryMovementListMax: result.inventoryMovementListMax,
335                                    inventoryItemPurchases: result.inventoryItemPurchases,
336                                    inventoryItemPurchasesTotal: result.inventoryItemPurchasesTotal,
337                                    showTab: result.showTab]
338
339            if(session.inventoryMovementTaskId) {
340                model.inventoryMovementInstance = new InventoryMovement()
341                model.inventoryMovementInstance.task = Task.get(session.inventoryMovementTaskId)
342                model.inventoryMovementInstance.quantity = 1
343            }
344
345            // Success.
346            return model
347        }
348
349        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
350        redirect(action:search)
351    }
352
353    def delete = {
354        def result = inventoryItemService.delete(params)
355
356        if(!result.error) {
357            flash.message = g.message(code: "default.delete.success", args: ["InventoryItem", params.id])
358            redirect(action:search)
359            return
360        }
361
362        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
363
364        if(result.error.code == "default.not.found") {
365            redirect(action:search)
366            return
367        }
368
369        redirect(action:show, id: params.id)
370    }
371
372    def edit = {
373
374        // In the case of an actionSubmit button, rewrite action name from 'index'.
375        if(params._action_Edit)
376            params.action='edit'
377
378        def result = inventoryItemService.edit(params)
379
380        if(!result.error) {
381            def possibleAlternateItems = inventoryItemService.getPossibleAlternateItems(result.inventoryItemInstance)
382            def suppliers = Supplier.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
383            def manufacturers = Manufacturer.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
384
385            return [ inventoryItemInstance : result.inventoryItemInstance,
386                            possibleAlternateItems: possibleAlternateItems,
387                            suppliers: suppliers,
388                            manufacturers: manufacturers]
389        }
390
391        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
392        redirect(action:search)
393    }
394
395    def update = {
396        def result = inventoryItemService.update(params)
397
398        if(!result.error) {
399            flash.message = g.message(code: "default.update.success", args: ["InventoryItem", params.id])
400            redirect(action:show, id: params.id)
401            return
402        }
403
404        if(result.error.code == "default.not.found") {
405            flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
406            redirect(action:search)
407            return
408        }
409
410        def possibleAlternateItems = inventoryItemService.getPossibleAlternateItems(result.inventoryItemInstance)
411        def suppliers = Supplier.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
412        def manufacturers = Manufacturer.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
413        render(view:'edit', model:[inventoryItemInstance: result.inventoryItemInstance.attach(),
414                                                possibleAlternateItems: possibleAlternateItems,
415                                                suppliers: suppliers,
416                                                manufacturers: manufacturers])
417    }
418
419    def create = {
420        def result = inventoryItemService.create(params)
421        def suppliers = Supplier.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
422        def manufacturers = Manufacturer.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
423
424        if(!result.error)
425            return [inventoryItemInstance: result.inventoryItemInstance,
426                            suppliers: suppliers,
427                            manufacturers: manufacturers]
428
429        //flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
430        redirect(action: search)
431    }
432
433    def save = {
434        def result = inventoryItemService.save(params)
435
436        if(!result.error) {
437            flash.message = g.message(code: "default.create.success", args: ["InventoryItem", result.inventoryItemInstance.id])
438            redirect(action:show, id: result.inventoryItemInstance.id)
439            return
440        }
441
442        def suppliers = Supplier.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
443        def manufacturers = Manufacturer.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
444
445        //flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
446        render(view:'create', model:[inventoryItemInstance: result.inventoryItemInstance,
447                                                    suppliers: suppliers,
448                                                    manufacturers: manufacturers])
449    }
450
451    /**
452    * Handles the use inventory item form submit in the show view.
453    */
454    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
455    def useInventoryItem = {
456
457        params.inventoryMovementType = InventoryMovementType.get(1) // Set type to "Used".
458        def result = inventoryMovementService.move(params)
459
460        if(!result.error) {
461            flash.message = "Inventory Movement for ${result.inventoryMovementInstance.inventoryItem.name.encodeAsHTML()} created."
462            session.inventoryMovementTaskId = null
463            redirect(controller: "taskDetailed",
464                            action: "show",
465                            id: result.taskId,
466                            params: [showTab: "showInventoryTab"])
467            // Success.
468            return
469        }
470
471        // Prepare data for the show view.
472        def p = [:]
473        p.id = result.inventoryMovementInstance.inventoryItem?.id
474        def r = inventoryItemService.show(p)
475
476        // Render show view if data was successfully prepared.
477        if(!r.error) {
478            def model = [ inventoryItemInstance: r.inventoryItemInstance,
479                                    inventoryMovementList: r.inventoryMovementList,
480                                    inventoryMovementListTotal: r.inventoryMovementListTotal,
481                                    inventoryMovementListMax: r.inventoryMovementListMax,
482                                    inventoryItemPurchases: r.inventoryItemPurchases,
483                                    inventoryItemPurchasesTotal: r.inventoryItemPurchasesTotal,
484                                    showTab: r.showTab]
485
486            model.inventoryMovementInstance = result.inventoryMovementInstance // This will pass in the errors.
487
488            render(view: 'show', model: model)
489            return
490        }
491
492        // Could not prepare data for show view so doing the next best thing.
493        flash.errorMessage = g.message(code: r.error.code, args: r.error.args)
494        redirect(action:search)
495
496    } // useInventoryItem
497
498    /**
499    * Clear the use inventory item form in the show view.
500    * Accomplished by clearing the session variable and ajax.
501    */
502    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
503    def clearUseInventoryItem = {
504            session.inventoryMovementTaskId = null
505            render ''
506    }
507
508} // end of class
Note: See TracBrowser for help on using the repository browser.