Index: grails-app/services/com/lemans/ds/solr/SolrQueryService.groovy =================================================================== diff -u -reb086951c8bc10945fe4f3e3545b092570561f58 -r92a4762c030eb6b32a4f08a4d1b9f62fab019d96 --- grails-app/services/com/lemans/ds/solr/SolrQueryService.groovy (.../SolrQueryService.groovy) (revision eb086951c8bc10945fe4f3e3545b092570561f58) +++ grails-app/services/com/lemans/ds/solr/SolrQueryService.groovy (.../SolrQueryService.groovy) (revision 92a4762c030eb6b32a4f08a4d1b9f62fab019d96) @@ -10,6 +10,7 @@ import org.apache.solr.common.util.SimpleOrderedMap import org.codehaus.groovy.runtime.InvokerHelper +import java.text.SimpleDateFormat import java.time.LocalDate import java.time.temporal.WeekFields import java.util.concurrent.CompletableFuture @@ -98,7 +99,7 @@ } userQueue } - + List adminOverview(QueuePayload payload) { List futures = [ queueCountsForPartsWithOutCategory(payload, pool), @@ -132,7 +133,9 @@ latestGoliveDate(payload, pool), earliestGoliveDate(payload, pool), partLastUpdated(payload, pool), - productLastUpdated(payload, pool) + partDaysBehind(payload, pool), + productLastUpdated(payload, pool), + productDaysBehind(payload, pool) ] List queueCounts = futures.stream().map { CompletableFuture future -> future.join() }.collect(Collectors.toList()) injectPastWeekCounts(queueCounts) @@ -245,27 +248,27 @@ } - private CompletableFuture latestGoliveDate(QueuePayload payload, Executor executor) { + private CompletableFuture earliestGoliveDate(QueuePayload payload, Executor executor) { CompletableFuture.supplyAsync(new Supplier() { @Override Map get() { - QueuePayload queuePayload = copyWithQueueType(payload, QueueType.PART_LATEST_GO_LIVE_DATE) + QueuePayload queuePayload = copyWithQueueType(payload, QueueType.PART_EARLIEST_GO_LIVE_DATE) SolrQuery query = new SolrQuery() - .addFilterQuery('(qcStatusCode:13001)') + .addFilterQuery('(qcStatusCode:13001)') query.add('json.facet', '{uniqueVals:{type:terms,field:userName,missing:true,mincount:1,limit:-1,facet:{date:"min(goliveDate)"}}}') addFacetFilters(query, queuePayload) buildResponseDate(dsQueueSolrClient.request(new QueryRequest(query)), queuePayload) } }, executor) } - private CompletableFuture earliestGoliveDate(QueuePayload payload, Executor executor) { + private CompletableFuture latestGoliveDate(QueuePayload payload, Executor executor) { CompletableFuture.supplyAsync(new Supplier() { @Override Map get() { - QueuePayload queuePayload = copyWithQueueType(payload, QueueType.PART_EARLIEST_GO_LIVE_DATE) + QueuePayload queuePayload = copyWithQueueType(payload, QueueType.PART_LATEST_GO_LIVE_DATE) SolrQuery query = new SolrQuery() - .addFilterQuery('(qcStatusCode:13001)') + .addFilterQuery('(qcStatusCode:13001)') query.add('json.facet', '{uniqueVals:{type:terms,field:userName,missing:true,mincount:1,limit:-1,facet:{date:"max(goliveDate)"}}}') addFacetFilters(query, queuePayload) buildResponseDate(dsQueueSolrClient.request(new QueryRequest(query)), queuePayload)} @@ -278,28 +281,56 @@ Map get() { QueuePayload queuePayload = copyWithQueueType(payload, QueueType.PART_LAST_UPDATED) SolrQuery query = new SolrQuery() - .addFilterQuery('(qcStatusCode:13001)') + .addFilterQuery('(qcStatusCode:13001)') query.add('json.facet', '{uniqueVals:{type:terms,field:userName,missing:true,limit:-1,facet:{date:"max(qcPartLastUpdated)"}}}') addFacetFilters(query, queuePayload) buildResponseDate(dsQueueSolrClient.request(new QueryRequest(query)), queuePayload) } }, executor) } + private CompletableFuture partDaysBehind(QueuePayload payload, Executor executor) { + CompletableFuture.supplyAsync(new Supplier() { + @Override + Map get() { + QueuePayload queuePayload = copyWithQueueType(payload, QueueType.PART_DAYS_BEHIND) + SolrQuery query = new SolrQuery() + .addFilterQuery('(qcStatusCode:13001)') + query.add('json.facet', '{uniqueVals:{type:terms,field:userName,missing:true,limit:-1,facet:{date:"max(qcPartLastUpdated)"}}}') + addFacetFilters(query, queuePayload) + buildResponseDaysBehind(dsQueueSolrClient.request(new QueryRequest(query)), queuePayload) + } + }, executor) + } + private CompletableFuture productLastUpdated(QueuePayload payload, Executor executor) { CompletableFuture.supplyAsync(new Supplier() { @Override Map get() { QueuePayload queuePayload = copyWithQueueType(payload, QueueType.PRODUCT_LAST_UPDATED) SolrQuery query = new SolrQuery() - .addFilterQuery('(qcProductStatusCode:13001)') + .addFilterQuery('(qcProductStatusCode:13001)') query.add('json.facet', '{uniqueVals:{type:terms,field:userName,missing:true,limit:-1,facet:{date:"max(qcProductLastUpdated)"}}}') addFacetFilters(query, queuePayload) buildResponseDate(dsQueueSolrClient.request(new QueryRequest(query)), queuePayload) } }, executor) } + private CompletableFuture productDaysBehind(QueuePayload payload, Executor executor) { + CompletableFuture.supplyAsync(new Supplier() { + @Override + Map get() { + QueuePayload queuePayload = copyWithQueueType(payload, QueueType.PRODUCT_DAYS_BEHIND) + SolrQuery query = new SolrQuery() + .addFilterQuery('(qcProductStatusCode:13001)') + query.add('json.facet', '{uniqueVals:{type:terms,field:userName,missing:true,limit:-1,facet:{date:"max(qcProductLastUpdated)"}}}') + addFacetFilters(query, queuePayload) + buildResponseDaysBehind(dsQueueSolrClient.request(new QueryRequest(query)), queuePayload) + } + }, executor) + } + private CompletableFuture categoryFacetsForProducts(QueuePayload payload, Executor executor) { CompletableFuture.supplyAsync(new Supplier() { @Override @@ -693,22 +724,32 @@ List buckets = uniqueVals?.get('buckets') List values = populateCardinalityValuesForDate(buckets, missing, payload) Optional> optionalResult = values?.stream() - ?.max{ obj1, obj2 -> - if (obj1?.date == null && obj2?.date == null) { - return 0 - } else if (obj1?.date == null) { - return 1 - } else if (obj2?.date == null) { - return -1 - } else { - return obj1?.date.compareTo(obj2?.date) - } - }?.orElse(null) + ?.min{ obj1, obj2 -> + if (obj1?.date == null && obj2?.date == null) { + return 0 + } else if (obj1?.date == null) { + return 1 + } else if (obj2?.date == null) { + return -1 + } else { + return obj1?.date.compareTo(obj2?.date) + } + }?.orElse(null) Date totalDate = optionalResult?.isPresent() ? optionalResult?.get()['date'] : null [type: payload.queueType.name(), displayName: payload.queueType.value, drillDowns: values ?: [], date: totalDate] } + private Map buildResponseDaysBehind(NamedList response, QueuePayload payload) { + SimpleOrderedMap facets = response.get('facets') + SimpleOrderedMap uniqueVals = facets ? facets.get('uniqueVals') : [:] + SimpleOrderedMap missing = uniqueVals?.get('missing') + List buckets = uniqueVals?.get('buckets') + List values = populateCardinalityValuesForDaysBehind(buckets, missing, payload) + Integer totalCount = values?.stream()?.mapToInt { a -> (Integer) a.count }?.min()?.getAsInt() + [type: payload.queueType.name(), displayName: payload.queueType.value, drillDowns: values ?: [], count: totalCount ?: 0] + } + private List populateCardinalityValuesForDate(List buckets, SimpleOrderedMap missing, QueuePayload payload) { List values if (payload.viewType == ViewType.ADMIN) { @@ -729,6 +770,50 @@ values } + private List populateCardinalityValuesForDaysBehind(List buckets, SimpleOrderedMap missing, QueuePayload payload) { + List values + if (payload.viewType == ViewType.ADMIN) { + // Collect values for ADMIN view + values = buckets?.collect { SimpleOrderedMap fieldStatsInfo -> + String dateString = fieldStatsInfo.get('date') as String + def timeDiff = calculateTimeDifference(dateString) + [userName: fieldStatsInfo.get('val'), count: timeDiff] + } + + // Handle missing date in missing map + if (missing?.get('date')) { + String dateString = missing.get('date') as String + def timeDiff = calculateTimeDifference(dateString) + values.add([userName: 'No User Assigned', count: timeDiff]) + } + } else { + // Collect values for non-ADMIN view + values = buckets?.collect { SimpleOrderedMap fieldStatsInfo -> + String dateString = fieldStatsInfo.get('date') as String + def timeDiff = calculateTimeDifference(dateString) + [categoryId: (fieldStatsInfo.get('val') ?: '')?.toInteger(), count: timeDiff] + } + + // Handle missing date in missing map + if (missing?.get('date')) { + String dateString = missing.get('date') as String + def timeDiff = calculateTimeDifference(dateString) + values.add([userName: 'No User Assigned', count: timeDiff]) + } + } + + values + } + + private def calculateTimeDifference(String dateString) { + SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.ENGLISH) + if (dateString != null) { + Date date = sdf.parse(dateString) + return date ? (date - new Date()) : 0 + } + return 0 + } + private Map buildResponse(QueryResponse response, QueuePayload payload) { Map facets = response.facetFields.collectEntries { FacetField facetField -> String key = treatedName(facetField.name)