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

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

Add feature to import inventory item pictures from zip file.

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