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

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

Add inventory item quick search (items below reorder) and remember user's search in session.

File size: 17.8 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 search unless a new search is being requested.
137        if(!params.quickSearch && !filterParams) {
138            if(session.inventoryItemQuickSearch)
139                params.quickSearch = session.inventoryItemQuickSearch
140            else if(session.inventoryItemSearchFilterParams) {
141                session.inventoryItemSearchFilterParams.each() { params[it.key] = it.value }
142                params.filter = session.inventoryItemSearchFilter
143                isFilterApplied = FilterUtils.isFilterApplied(params)
144            }
145        }
146
147        // Remember sort if supplied, otherwise try to restore.
148        if(params.sort && params.order) {
149             session.inventoryItemSearchSort = params.sort
150             session.inventoryItemSearchOrder = params.order
151        }
152        else if(session.inventoryItemSearchSort && session.inventoryItemSearchOrder) {
153            params.sort = session.inventoryItemSearchSort
154            params.order = session.inventoryItemSearchOrder
155        }
156
157        if(isFilterApplied) {
158            // filterPane:
159            inventoryItemInstanceList = filterService.filter( params, InventoryItem )
160            inventoryItemInstanceTotal = filterService.count( params, InventoryItem )
161            filterParams = com.zeddware.grails.plugins.filterpane.FilterUtils.extractFilterParams(params)
162            // Remember search.
163            session.inventoryItemSearchFilterParams = new LinkedHashMap(filterParams)
164            session.inventoryItemSearchFilter = new LinkedHashMap(params.filter)
165            session.inventoryItemQuickSearch = null
166        }
167        else {
168            // Quick Search:
169            if(!params.quickSearch) params.quickSearch = "all"
170            def result = inventoryItemSearchService.getQuickSearch(params, RCU.getLocale(request))
171            inventoryItemInstanceList = result.inventoryItemList
172            inventoryItemInstanceTotal = result.inventoryItemList.totalCount
173            params.message = result.message
174            filterParams.quickSearch = result.quickSearch
175            // Remember search.
176            session.inventoryItemSearchFilterParams = null
177            session.inventoryItemSearchFilter = null
178            session.inventoryItemQuickSearch = result.quickSearch
179        }
180
181        // export plugin:
182        if(params?.format && params.format != "html") {
183
184            def dateFmt = { date ->
185                formatDate(format: "EEE, dd-MMM-yyyy", date: date)
186            }
187
188            String title
189            if(params.quickSearch)
190                title = params.message
191            else
192                title = "Filtered Inventory List."
193
194            response.contentType = ConfigurationHolder.config.grails.mime.types[params.format]
195            response.setHeader("Content-disposition", "attachment; filename=Inventory.${params.extension}")
196            List fields = ["name",
197                                "description",
198                                "unitsInStock",
199                                "reorderPoint",
200                                "unitOfMeasure",
201                                "inventoryLocation",
202                                "inventoryLocation.inventoryStore"]
203            Map labels = ["name": "Name",
204                                "description": "Description",
205                                "unitsInStock":"In Stock",
206                                "reorderPoint":"Reorder Point",
207                                "unitOfMeasure": "UOM",
208                                "inventoryLocation": "Location",
209                                "inventoryLocation.inventoryStore": "Store"]
210
211            Map formatters = [:]
212            Map parameters = [title: title, separator: ","]
213
214            exportService.export(params.format,
215                                                response.outputStream,
216                                                inventoryItemInstanceList.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) },
217                                                fields,
218                                                labels,
219                                                formatters,
220                                                parameters)
221        }
222
223        // Add some basic params to filterParams.
224        filterParams.max = params.max
225        filterParams.offset = params.offset?.toInteger() ?: 0
226        filterParams.sort = params.sort ?: "name"
227        filterParams.order = params.order ?: "asc"
228
229        return[ inventoryItemInstanceList: inventoryItemInstanceList,
230                inventoryItemInstanceTotal: inventoryItemInstanceTotal,
231                filterParams: filterParams,
232                params: params ]
233    } // end search()
234
235    /**
236    * Simply assigns a passed in task id to a session variable and redirects to search.
237    */
238    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
239    def findInventoryItemForMovement = {
240        if(!params.task?.id) {
241            flash.message = "No task id supplied, please select a task then the inventory tab."
242            redirect(controller: "taskDetailed", action: "search")
243            return
244        }
245
246        session.inventoryMovementTaskId = params.task.id
247        flash.message = "Please find and then select the inventory item."
248        redirect(action: search)
249    }
250
251    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
252    def show = {
253
254        // In the case of an actionSubmit button, rewrite action name from 'index'.
255        if(params._action_Show)
256            params.action='show'
257
258        def result = inventoryItemService.show(params)
259
260        if(!result.error) {
261
262            def model = [ inventoryItemInstance: result.inventoryItemInstance,
263                                    inventoryMovementList: result.inventoryMovementList,
264                                    inventoryMovementListTotal: result.inventoryMovementListTotal,
265                                    inventoryMovementListMax: result.inventoryMovementListMax,
266                                    inventoryItemPurchases: result.inventoryItemPurchases,
267                                    inventoryItemPurchasesTotal: result.inventoryItemPurchasesTotal,
268                                    showTab: result.showTab]
269
270            if(session.inventoryMovementTaskId) {
271                model.inventoryMovementInstance = new InventoryMovement()
272                model.inventoryMovementInstance.task = Task.get(session.inventoryMovementTaskId)
273                model.inventoryMovementInstance.quantity = 1
274            }
275
276            // Success.
277            return model
278        }
279
280        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
281        redirect(action:search)
282    }
283
284    def delete = {
285        def result = inventoryItemService.delete(params)
286
287        if(!result.error) {
288            flash.message = g.message(code: "default.delete.success", args: ["InventoryItem", params.id])
289            redirect(action:search)
290            return
291        }
292
293        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
294
295        if(result.error.code == "default.not.found") {
296            redirect(action:search)
297            return
298        }
299
300        redirect(action:show, id: params.id)
301    }
302
303    def edit = {
304
305        // In the case of an actionSubmit button, rewrite action name from 'index'.
306        if(params._action_Edit)
307            params.action='edit'
308
309        def result = inventoryItemService.edit(params)
310
311        if(!result.error) {
312            def possibleAlternateItems = inventoryItemService.getPossibleAlternateItems(result.inventoryItemInstance)
313            def suppliers = Supplier.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
314            def manufacturers = Manufacturer.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
315
316            return [ inventoryItemInstance : result.inventoryItemInstance,
317                            possibleAlternateItems: possibleAlternateItems,
318                            suppliers: suppliers,
319                            manufacturers: manufacturers]
320        }
321
322        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
323        redirect(action:search)
324    }
325
326    def update = {
327        def result = inventoryItemService.update(params)
328
329        if(!result.error) {
330            flash.message = g.message(code: "default.update.success", args: ["InventoryItem", params.id])
331            redirect(action:show, id: params.id)
332            return
333        }
334
335        if(result.error.code == "default.not.found") {
336            flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
337            redirect(action:search)
338            return
339        }
340
341        def possibleAlternateItems = inventoryItemService.getPossibleAlternateItems(result.inventoryItemInstance)
342        def suppliers = Supplier.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
343        def manufacturers = Manufacturer.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
344        render(view:'edit', model:[inventoryItemInstance: result.inventoryItemInstance.attach(),
345                                                possibleAlternateItems: possibleAlternateItems,
346                                                suppliers: suppliers,
347                                                manufacturers: manufacturers])
348    }
349
350    def create = {
351        def result = inventoryItemService.create(params)
352        def suppliers = Supplier.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
353        def manufacturers = Manufacturer.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
354
355        if(!result.error)
356            return [inventoryItemInstance: result.inventoryItemInstance,
357                            suppliers: suppliers,
358                            manufacturers: manufacturers]
359
360        //flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
361        redirect(action: search)
362    }
363
364    def save = {
365        def result = inventoryItemService.save(params)
366
367        if(!result.error) {
368            flash.message = g.message(code: "default.create.success", args: ["InventoryItem", result.inventoryItemInstance.id])
369            redirect(action:show, id: result.inventoryItemInstance.id)
370            return
371        }
372
373        def suppliers = Supplier.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
374        def manufacturers = Manufacturer.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
375
376        //flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
377        render(view:'create', model:[inventoryItemInstance: result.inventoryItemInstance,
378                                                    suppliers: suppliers,
379                                                    manufacturers: manufacturers])
380    }
381
382    /**
383    * Handles the use inventory item form submit in the show view.
384    */
385    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
386    def useInventoryItem = {
387
388        params.inventoryMovementType = InventoryMovementType.get(1) // Set type to "Used".
389        def result = inventoryMovementService.move(params)
390
391        if(!result.error) {
392            flash.message = "Inventory Movement for ${result.inventoryMovementInstance.inventoryItem.name.encodeAsHTML()} created."
393            session.inventoryMovementTaskId = null
394            redirect(controller: "taskDetailed",
395                            action: "show",
396                            id: result.taskId,
397                            params: [showTab: "showInventoryTab"])
398            // Success.
399            return
400        }
401
402        // Prepare data for the show view.
403        def p = [:]
404        p.id = result.inventoryMovementInstance.inventoryItem?.id
405        def r = inventoryItemService.show(p)
406
407        // Render show view if data was successfully prepared.
408        if(!r.error) {
409            def model = [ inventoryItemInstance: r.inventoryItemInstance,
410                                    inventoryMovementList: r.inventoryMovementList,
411                                    inventoryMovementListTotal: r.inventoryMovementListTotal,
412                                    inventoryMovementListMax: r.inventoryMovementListMax,
413                                    inventoryItemPurchases: r.inventoryItemPurchases,
414                                    inventoryItemPurchasesTotal: r.inventoryItemPurchasesTotal,
415                                    showTab: r.showTab]
416
417            model.inventoryMovementInstance = result.inventoryMovementInstance // This will pass in the errors.
418
419            render(view: 'show', model: model)
420            return
421        }
422
423        // Could not prepare data for show view so doing the next best thing.
424        flash.errorMessage = g.message(code: r.error.code, args: r.error.args)
425        redirect(action:search)
426
427    } // useInventoryItem
428
429    /**
430    * Clear the use inventory item form in the show view.
431    * Accomplished by clearing the session variable and ajax.
432    */
433    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser'])
434    def clearUseInventoryItem = {
435            session.inventoryMovementTaskId = null
436            render ''
437    }
438
439} // end of class
Note: See TracBrowser for help on using the repository browser.