Index: /trunk/grails-app/conf/Config.groovy =================================================================== --- /trunk/grails-app/conf/Config.groovy (revision 645) +++ /trunk/grails-app/conf/Config.groovy (revision 646) @@ -209,5 +209,6 @@ [order:20, controller:'inventoryItemDetailed', title:'Create', action:'create', isVisible: { true }], [order:90, controller:'inventoryItemDetailed', title:'Show', action:'show', isVisible: { params.action == 'show' }], - [order:91, controller:'inventoryItemDetailed', title:'Edit', action:'edit', isVisible: { params.action == 'edit' }] + [order:91, controller:'inventoryItemDetailed', title:'Edit', action:'edit', isVisible: { params.action == 'edit' }], + [order:91, controller:'inventoryItemDetailed', title:'Reorder', action:'reorder', isVisible: { params.action == 'reorder' }] ] ], Index: /trunk/grails-app/controllers/InventoryItemDetailedController.groovy =================================================================== --- /trunk/grails-app/controllers/InventoryItemDetailedController.groovy (revision 645) +++ /trunk/grails-app/controllers/InventoryItemDetailedController.groovy (revision 646) @@ -34,4 +34,20 @@ } forward(action: 'search', params: params) + } + + /** + * Set session.inventoryItemReorderSearchParamsMax + */ + @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager', 'ROLE_InventoryUser']) + def setReorderSearchParamsMax = { + def max = 1000 + if(params.newMax?.isInteger()) { + def i = params.newMax.toInteger() + if(i > 0 && i <= max) + session.inventoryItemReorderSearchParamsMax = params.newMax + if(i > max) + session.inventoryItemReorderSearchParamsMax = max + } + forward(action: 'reorder', params: params) } @@ -542,3 +558,154 @@ } + /** + * Search for Inventory items that require reorder. + */ + @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_InventoryManager']) + def reorder = { + + // In the case of an actionSubmit button, rewrite action name from 'index'. + if(params._action_reorder) + params.action='reorder' + + if(session.inventoryItemReorderSearchParamsMax) + params.max = session.inventoryItemReorderSearchParamsMax + + def inventoryItemInstanceList = [] + def inventoryItemInstanceTotal + def filterParams = params + def suppliers = Supplier.findAllByIsActive(true).sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) } + def inventoryGroups = InventoryGroup.findAllByIsActive(true) + if(!params.selectedGroups) + params.selectedGroups = inventoryGroups.collect{it.id} + else + params.selectedGroups = params.selectedGroups.collect { it.toLong() } + + // Restore search unless a new search is being requested. + if(!params.newSearch && !params.quickSearch) { + if(session.reorderSearchSelectedGroups) { + params.selectedGroups = session.reorderSearchSelectedGroups + params.selectedSupplier = session.reorderSearchSelectedSupplier + params.includeAlternateSuppliers = session.reorderSearchIncludeAlternateSuppliers + params.includeReorderListingDisabled = session.reorderSearchIncludeReorderListingDisabled + params.includeOnBackOrder = session.reorderSearchIncludeOnBackOrder + } + else if(session.inventoryItemReorderQuickSearch) { + params.quickSearch = session.inventoryItemReorderQuickSearch + if(session.inventoryItemReorderQuickSearchDaysBack) + params.daysBack = session.inventoryItemReorderQuickSearchDaysBack.toString() + } + } + + // Remember sort if supplied, otherwise try to restore. + if(params.sort && params.order) { + session.inventoryItemReorderSearchSort = params.sort + session.inventoryItemReorderSearchOrder = params.order + } + else if(session.inventoryItemReorderSearchSort && session.inventoryItemReorderSearchOrder) { + params.sort = session.inventoryItemReorderSearchSort + params.order = session.inventoryItemReorderSearchOrder + } + + if(params.quickSearch) { + // Quick Search Links: + if(!params.quickSearch) params.quickSearch = "inventoryBelowReorder" + def result = inventoryItemSearchService.getQuickSearch(params, RCU.getLocale(request)) + inventoryItemInstanceList = result.inventoryItemList + inventoryItemInstanceTotal = result.inventoryItemList.totalCount + params.message = result.message + filterParams.quickSearch = result.quickSearch + // Remember search. + session.inventoryItemReorderQuickSearch = result.quickSearch + if(result.daysBack) + session.inventoryItemReorderQuickSearchDaysBack = result.daysBack + // Clear any previous search. + session.removeAttribute("reorderSearchSelectedGroups") + session.removeAttribute("reorderSearchSelectedSupplier") + session.removeAttribute("reorderSearchIncludeAlternateSuppliers") + session.removeAttribute("reorderSearchIncludeReorderListingDisabled") + session.removeAttribute("reorderSearchIncludeOnBackOrder") + } + else { + // Reorder Search: + def result = inventoryItemSearchService.getReorderSearch(params, RCU.getLocale(request)) + inventoryItemInstanceList = result.inventoryItemList + inventoryItemInstanceTotal = result.inventoryItemList.totalCount + params.message = result.message + // Place limit search selects in filterParams for pagination. + if(params.selectedGroups) { + filterParams.selectedGroups = params.selectedGroups + filterParams.selectedSupplier = params.selectedSupplier + filterParams.includeAlternateSuppliers = params.includeAlternateSuppliers + filterParams.includeReorderListingDisabled = params.includeReorderListingDisabled + filterParams.includeOnBackOrder = params.includeOnBackOrder + } + // Remember search. + session.reorderSearchSelectedGroups = params.selectedGroups + session.reorderSearchSelectedSupplier = params.selectedSupplier + session.reorderSearchIncludeAlternateSuppliers = params.includeAlternateSuppliers + session.reorderSearchIncludeReorderListingDisabled = params.includeReorderListingDisabled + session.reorderSearchIncludeOnBackOrder = params.includeOnBackOrder + // Clear any previous search. + session.removeAttribute("inventoryItemReorderQuickSearch") + session.removeAttribute("inventoryItemReorderQuickSearchDaysBack") + } + + // export plugin: + if(params?.format && params.format != "html") { + + def dateFmt = { date -> + formatDate(format: "EEE, dd-MMM-yyyy", date: date) + } + + String title + if(params.quickSearch) + title = params.message + else + title = "Filtered Inventory List." + + response.contentType = ConfigurationHolder.config.grails.mime.types[params.format] + response.setHeader("Content-disposition", "attachment; filename=Inventory.${params.extension}") + List fields = ["name", + "description", + "inventoryGroup", + "unitsInStock", + "reorderPoint", + "unitOfMeasure", + "inventoryLocation", + "inventoryLocation.inventoryStore"] + Map labels = ["name": "Name", + "description": "Description", + "inventoryGroup": "Group", + "unitsInStock":"In Stock", + "reorderPoint":"Reorder Point", + "unitOfMeasure": "UOM", + "inventoryLocation": "Location", + "inventoryLocation.inventoryStore": "Store"] + + Map formatters = [:] + Map parameters = [title: title, separator: ","] + + exportService.export(params.format, + response.outputStream, + inventoryItemInstanceList.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }, + fields, + labels, + formatters, + parameters) + } + + // Add some basic params to filterParams. + filterParams.max = params.max + filterParams.offset = params.offset?.toInteger() ?: 0 + filterParams.sort = params.sort ?: "name" + filterParams.order = params.order ?: "asc" + + return[ inventoryItemInstanceList: inventoryItemInstanceList, + inventoryItemInstanceTotal: inventoryItemInstanceTotal, + filterParams: filterParams, + params: params, + inventoryGroups: inventoryGroups, + suppliers: suppliers] + } // end reorder() + } // end of class Index: /trunk/grails-app/services/InventoryItemSearchService.groovy =================================================================== --- /trunk/grails-app/services/InventoryItemSearchService.groovy (revision 645) +++ /trunk/grails-app/services/InventoryItemSearchService.groovy (revision 646) @@ -1,2 +1,3 @@ +import net.kromhouts.HqlBuilder import grails.orm.PagedResultList import org.compass.core.engine.SearchEngineQueryParseException @@ -104,4 +105,80 @@ } // createCriteria } // getInventoryBelowReorder + + /** + * Search for inventory items that are below reorder point. + * @param params The request params. + * @param locale The locale to use when generating result.message. + */ + def getReorderSearch(params, locale) { + def result = [:] + + def getMessage = { Map m -> + messageSource.getMessage(m.code, m.args == null ? null : m.args.toArray(), locale) + } + + params.max = Math.min(params?.max?.toInteger() ?: 10, paramsMax) + params.offset = params?.offset?.toInteger() ?: 0 + + def sort = "inventoryItem." + (params?.sort ?: "name") + def order = params?.order == "desc" ? "desc" : "asc" + + def q = new HqlBuilder(max: params.max, offset: params.offset).query { + select 'count(distinct inventoryItem) as inventoryItemCount' + from 'InventoryItem as inventoryItem', + 'left join inventoryItem.alternateSuppliers as alternateSupplier' + where 'inventoryItem.unitsInStock <= inventoryItem.reorderPoint' + and 'inventoryItem.isActive = true' + and 'inventoryItem.isObsolete = false' + + if(!params.includeReorderListingDisabled) + and "inventoryItem.enableReorderListing = true" + + if(params.selectedSupplier?.isLong()) { + namedParams.supplier = Supplier.get(params.selectedSupplier.toLong()) + if(params.includeAlternateSuppliers) + and "(inventoryItem.preferredSupplier = :supplier or alternateSupplier = :supplier)" + else + and "inventoryItem.preferredSupplier = :supplier" + } // if selectedSupplier + + if(params.selectedGroups) { + namedParams.selectedGroupIds = params.selectedGroups + and "inventoryItem.inventoryGroup.id in(:selectedGroupIds)" + } + + if(!params.includeOnBackOrder) { + // Sub query! + def onBackOrder = new HqlBuilder().query { + from "InventoryItemPurchase p" + where "p.inventoryItem = inventoryItem" + and "p.inventoryItem = inventoryItem" + and "p.inventoryItemPurchaseType.id = 1" // Order Placed. + and "p.receivedComplete = false" + } + + and "not exists ($onBackOrder.query)" + } + + } // query + + def totalCount = InventoryItem.executeQuery(q.query, q.namedParams)[0].toInteger() + + q.select = 'distinct inventoryItem' + q.order = "by $sort $order, inventoryItem.id asc" + def list = InventoryItem.executeQuery(q.query, q.namedParams, q.paginateParams) + + result.inventoryItemList = new PagedResultList(list, totalCount) + + // Get the result message. + if(result.inventoryItemList.totalCount > 0) + result.message = getMessage(code:"inventoryItem.search.text.below.reorder.description") + else + result.message = getMessage(code:"inventoryItem.search.text.below.reorder.none.found") + + // Success. + return result + + } // getReorderSearch /** Index: /trunk/grails-app/views/inventoryItemDetailed/reorder.gsp =================================================================== --- /trunk/grails-app/views/inventoryItemDetailed/reorder.gsp (revision 646) +++ /trunk/grails-app/views/inventoryItemDetailed/reorder.gsp (revision 646) @@ -0,0 +1,307 @@ + + + +
+ + ++ + | +
+ |
+
+ + | +
+ |
+
+ | +
+ |
+
+ | +
+ |
+
+ | +
+ |
+
Picture | +Description | + ++ + |
---|---|---|
+ |
+
+
+ ${fieldValue(bean:inventoryItemInstance, field:'name')} + ${fieldValue(bean:inventoryItemInstance, field:'description')} + + + Comment: + ${inventoryItemInstance.comment?.encodeAsHTML()} + + + Reorder Point: ${fieldValue(bean:inventoryItemInstance, field:'reorderPoint')} + ${fieldValue(bean:inventoryItemInstance, field:'unitOfMeasure')} + + P.Supplier: ${fieldValue(bean:inventoryItemInstance, field:'preferredSupplier')} + |
+
+ + ${fieldValue(bean:inventoryItemInstance, field:'inventoryGroup')} + | + ++ ${fieldValue(bean:inventoryItemInstance, field:'unitsInStock')} + ${fieldValue(bean:inventoryItemInstance, field:'unitOfMeasure')} + | + +
+ |
+
+
+