package com.genpt.nsight.v4.service.impl; import com.genpt.nsight.NSightCache; import com.genpt.nsight.config.NSightProperties; import com.genpt.nsight.v1.model.HeaderResponse; import com.genpt.nsight.v1.model.QuantityFreePaid; import com.genpt.nsight.v1.model.dto.SiteDTO; import com.genpt.nsight.v4.AvailabilityServiceContextV4; import com.genpt.nsight.v4.SplunkLogger; import com.genpt.nsight.v4.model.*; import com.genpt.nsight.v4.service.ProductAvailabilityAggregateV4; import com.genpt.nsight.v4.service.ProductAvailabilityFreePaidServiceV4; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @Service("ProductAvailabilityAggregateV4") public class ProductAvailabilityAggregateV4Impl implements ProductAvailabilityAggregateV4 { @Autowired NSightCache nSightCache; private static final Logger LOGGER = LoggerFactory.getLogger(ProductAvailabilityAggregateV4Impl.class); @Autowired NSightProperties nSightProperties; private ProductAvailabilityFreePaidServiceV4 productAvailabilityFreePaidServiceV4; @Autowired public void setProductAvailabilityFreePaidServiceV4(ProductAvailabilityFreePaidServiceV4 productAvailabilityFreePaidServiceV4) { this.productAvailabilityFreePaidServiceV4 = productAvailabilityFreePaidServiceV4; } @Override public ProductAvailabilityAggResponseProlink getProductAvailability(AvailabilityServiceContextV4 availabilityServiceContextV4) { SplunkLogger splunkLogger = new SplunkLogger(availabilityServiceContextV4.getRequest().getHeaderRequest()); long startTime = System.currentTimeMillis(); /* final ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")); if(availabilityServiceContextV4.getTimeOfDay() == 0L) { availabilityServiceContextV4.setDayOfWeek(now.getDayOfWeek().getValue() - 1); availabilityServiceContextV4.setTimeOfDay(availabilityServiceContextV4.getMillisFromMidnight(now)); } final ZonedDateTime beginningOfDay = now.truncatedTo(ChronoUnit.DAYS);*/ String siteId = nSightCache.getAliasToSiteIdMap().get(availabilityServiceContextV4.getRequest().getHeaderRequest().getRequestor().getRequestorIdentifier().getType() + "|" + availabilityServiceContextV4.getRequest().getHeaderRequest().getRequestor().getRequestorIdentifier().getValue()); SiteDTO callingStoreDTO = nSightCache.getSiteIdToSiteMap().get(siteId); if(callingStoreDTO.getTimeZone() == null || callingStoreDTO.getTimeZone().equalsIgnoreCase("NAN")) { com.genpt.nsight.v4.model.ProductAvailabilityAggResponseProlink productAvailabilityResponseFreePaid = availabilityServiceContextV4.getProductAvailabilityResponseProlink(availabilityServiceContextV4); LOGGER.error(splunkLogger.toString() + " Invalid Data - Timezone is null in NSight for requesting site: 3005"); productAvailabilityResponseFreePaid.setTracking(availabilityServiceContextV4.createInvalidTimezoneTracking()); return productAvailabilityResponseFreePaid; } if (nSightCache.getStoreHoursList().get(callingStoreDTO.getSiteIdentifier()) == null){ com.genpt.nsight.v4.model.ProductAvailabilityAggResponseProlink productAvailabilityResponseFreePaid = availabilityServiceContextV4.getProductAvailabilityResponseProlink(availabilityServiceContextV4); LOGGER.error(splunkLogger.toString() + " Invalid Data - No Store hours is null in NSight for requesting site: 3005"); productAvailabilityResponseFreePaid.setTracking(availabilityServiceContextV4.createInvalidStoreHoursTracking()); return productAvailabilityResponseFreePaid; } if(callingStoreDTO.getTimeZoneID() == null ) { com.genpt.nsight.v4.model.ProductAvailabilityAggResponseProlink productAvailabilityResponseFreePaid = availabilityServiceContextV4.getProductAvailabilityResponseProlink(availabilityServiceContextV4); LOGGER.error(splunkLogger.toString() + " Invalid Data - Timezone ID is null in NSight for requesting site: 3005"); productAvailabilityResponseFreePaid.setTracking(availabilityServiceContextV4.createInvalidTimezoneIDTracking()); return productAvailabilityResponseFreePaid; } if(availabilityServiceContextV4.getTimeOfDay() == 0L) { availabilityServiceContextV4.setDayOfWeekLocalStore(callingStoreDTO); } long buildResponseStartTime = System.currentTimeMillis(); ProductAvailabilityAggResponseProlink productAvailabilityAggResponse = new ProductAvailabilityAggResponseProlink(); productAvailabilityAggResponse.setCorrelationId(availabilityServiceContextV4.getCorrelationID()); HeaderResponse headerResponse = new HeaderResponse(); headerResponse.setCountryCode(availabilityServiceContextV4.getRequest().getHeaderRequest().getCountryCode()); headerResponse.setLanguageCode(availabilityServiceContextV4.getRequest().getHeaderRequest().getLanguageCode()); headerResponse.setRequestor(availabilityServiceContextV4.getRequest().getHeaderRequest().getRequestor()); headerResponse.setResponder(availabilityServiceContextV4.getRequest().getHeaderRequest().getResponder()); headerResponse.setTimestamp(Long.valueOf(availabilityServiceContextV4.getRequest().getHeaderRequest().getTimestamp())); productAvailabilityAggResponse.setHeaderResponse(headerResponse); DetailResponseAggProlink detailResponseAggNOL= new DetailResponseAggProlink(); detailResponseAggNOL.setDeliveryOffSets(availabilityServiceContextV4.getRequest().getDetailRequest().getDeliveryOffSets()); detailResponseAggNOL.setSubBuckets(availabilityServiceContextV4.getRequest().getDetailRequest().getSubBuckets()); productAvailabilityAggResponse.setDetailResponse(detailResponseAggNOL); //call the V4 free paid service ProductAvailabilityResponseFreePaid productAvailabilityResponseFreePaid = productAvailabilityFreePaidServiceV4.getProductAvailability(availabilityServiceContextV4, false); //based on the free paid derive the aggregates //go over all the parts productAvailabilityAggResponse.setTracking(productAvailabilityResponseFreePaid.getTracking()); productAvailabilityResponseFreePaid.getDetailResponse().getParts().forEach(part -> {// at each part level //if (part.getQuantities()!=null && part.getQuantities().size() > 0){ if (part.getQuantities()!=null){ Map bucketMap = new HashMap<>();//map of buckename to Bucket(LocalStore, Today, etc) List partAggNOLs = productAvailabilityAggResponse.getDetailResponse().getParts(); if (partAggNOLs == null) { partAggNOLs = new ArrayList(); productAvailabilityAggResponse.getDetailResponse().setParts(partAggNOLs); } //populate this part PartAggProlink partAggNOL = new PartAggProlink(); partAggNOL.setLineAbbrev(part.getLineAbbrev()); partAggNOL.setPartNumber(part.getPartNumber()); partAggNOL.setTracking(part.getTracking()); if (part.getPrice()!=null) partAggNOL.setPrice(part.getPrice()); if (part.getProductKit()!=null) partAggNOL.setProductKit(part.getProductKit()); if (part.getSuperSedes()!=null) partAggNOL.setSuperSedes(part.getSuperSedes()); BucketQuantityProlink bucketQuantity= partAggNOL.getQuantities(); if (bucketQuantity==null){//local bucket does not exist bucketQuantity = new BucketQuantityProlink(); bucketQuantity.setBuckets(new ArrayList<>()); partAggNOL.setQuantities(bucketQuantity); } // now iterate quantities from each site to create the buckets for (QuantityFreePaid quantityFreePaid : part.getQuantities()){//eseentiall iterating sites for a part if (quantityFreePaid.getAvailable().intValue() > 0) {//only interested in positive values //Create the Local Store bucket if calling store String currentSiteID = quantityFreePaid.getSiteUUID(); if (currentSiteID.equals(availabilityServiceContextV4.getRequestingSite().getSiteIdentifier())) {//local store createLocalBucket(bucketMap, quantityFreePaid, availabilityServiceContextV4, bucketQuantity); } else if (availabilityServiceContextV4.getRequestingSite().getMainCounterFlag()==true && availabilityServiceContextV4.getPrimaryDC() !=null && currentSiteID.compareToIgnoreCase(availabilityServiceContextV4.getPrimaryDC().getSiteId()) ==0) { //store is a main counter so add the DC quantity to local bucket createLocalBucket(bucketMap, quantityFreePaid, availabilityServiceContextV4, bucketQuantity);//main counts local store } else { // we are interested only in sites that have deliveries for aggregation List deliveryList = availabilityServiceContextV4.getDeliveryBySiteSorted().get(currentSiteID); if (deliveryList != null && deliveryList.size() > 0) {// has deliveries. ideally we should be interested in only the first one //need to know if this site has any free delivery boolean hasFreeDelivery=false; for (Delivery delivery : deliveryList) {//iterate deliveries if (delivery.getCutOffDateTime() != null && !nSightProperties.getPaidMOTS().contains(delivery.getDeliveryType())) {//cutoff times will always be after current time //found a free delivery hasFreeDelivery=true; ///convert to LocalDate time the expected range ZonedDateTime quickest = delivery.getDeliveryEstimate().getQuickestExpectationOfAllMin(); //the call is made within store hours //if (availabilityServiceContextV4.isStoreOpenIndicator()) if (!availabilityServiceContextV4.isAfterStoreHours()) {//only then can be in todays bucket // do we have any deliveries that can be done today. also check if its within after applying the offset if (availabilityServiceContextV4.getToday1CutoffTime() != null) {//can have two subbucekts if (quickest.isBefore(availabilityServiceContextV4.getToday1CutoffTime().withZoneSameLocal(ZoneOffset.of(availabilityServiceContextV4.getStoreTimeZone())))) { //can be got in the first Today1 subbucket for day createOrUpdateTodayTomorrowBucket(delivery, "Today1", bucketMap, quantityFreePaid, availabilityServiceContextV4, bucketQuantity); break;//from this delivery } else {//after today1 cutofftime if (quickest.isBefore(availabilityServiceContextV4.getStoreClose().withZoneSameLocal(ZoneOffset.of(availabilityServiceContextV4.getStoreTimeZone())))) { //goes into Today2 sub bucket createOrUpdateTodayTomorrowBucket(delivery, "Today2", bucketMap, quantityFreePaid, availabilityServiceContextV4, bucketQuantity); break; } else {//its after store close. so could be tomorrow ot plus2 bucket //check for tomorrow cutoff offset insertIntoTomorrowOrPlus2(delivery,availabilityServiceContextV4, bucketMap, quantityFreePaid, bucketQuantity); break; } } } else {//can have only one sub bucket today //we are within store hours. check if expected max is also within store hours // need to keep the time the same but change the offset to Standard so the compare works correctly if (quickest.isBefore(availabilityServiceContextV4.getStoreClose().withZoneSameLocal(ZoneOffset.of(availabilityServiceContextV4.getStoreTimeZone()))) && !availabilityServiceContextV4.isStoreHolidayToday()) { createOrUpdateTodayTomorrowBucket(delivery, "Today", bucketMap, quantityFreePaid, availabilityServiceContextV4, bucketQuantity); break; } else {//can be tomorrow or plus2 bucket insertIntoTomorrowOrPlus2(delivery, availabilityServiceContextV4, bucketMap, quantityFreePaid, bucketQuantity); break; } } }//outside store hours else {//store closed, can have only tomorrow abd plus 2 insertIntoTomorrowOrPlus2(delivery, availabilityServiceContextV4, bucketMap, quantityFreePaid, bucketQuantity); break; } }//valid free delivery type }//each delivery but only looking at free //now we can create a black bucket if necessary if we have not contributed to one of the free buckets if (!hasFreeDelivery){ for (Delivery delivery : deliveryList) {//iterate deliveries which should only be paid //check for paid ones for the Black bucket. this means there were no free deliveries for this site //or the paid delivery is the best delivery for this site if (delivery.getCutOffDateTime() != null && nSightProperties.getPaidMOTS().contains(delivery.getDeliveryType())) {//cutoff times will always be after current time //just pick the fasted paid to create the black bucket createorUpdateBlackBucket( delivery, availabilityServiceContextV4, bucketMap, quantityFreePaid , bucketQuantity ); break;/// since a delivery from a site can contribute to only 1 bucket, need the first paid }// this is a paid delivery }// for each paid delivery }//didnt have any free delivery }//has more than 0 deliveries }//else , not localstore and not main store //check if its a supplier and with no delivery options. if it had otpions it would have been in one of the above buckets List deliveryList = availabilityServiceContextV4.getDeliveryBySiteSorted().get(currentSiteID); // an assumption here is the main counter for a DC is not a site of type supplier if (nSightCache.getSiteIdToSiteMap().get(currentSiteID).getSiteType().compareToIgnoreCase("Supplier")==0){ if (deliveryList==null || (deliveryList!=null && deliveryList.size()==0)) createOrUpdateGreyBucket( availabilityServiceContextV4, currentSiteID, quantityFreePaid, bucketMap, bucketQuantity); } //done with a site at this point }else{ LOGGER.debug(splunkLogger.toString() + " Dropping Site {} since quantity is {} ", quantityFreePaid.getSiteUUID(), quantityFreePaid.getAvailable().intValue() ); } } partAggNOLs.add(partAggNOL); }//valid part });//for each part LOGGER.debug(splunkLogger.toString() + " Time taken to build response = {} ", (System.currentTimeMillis() - buildResponseStartTime)); LOGGER.info(splunkLogger.toString() + " Total time within NOLAggregate MicroService = {}",(System.currentTimeMillis() - startTime)); return productAvailabilityAggResponse; } private void createOrUpdateGreyBucket(AvailabilityServiceContextV4 availabilityServiceContextV4, String currentSiteID, QuantityFreePaid quantityFreePaid, Map bucketMap, BucketQuantityProlink bucketQuantity){ List deliveryList = availabilityServiceContextV4.getDeliveryBySiteSorted().get(currentSiteID); if (deliveryList == null || deliveryList.size() == 0) { String buckeName = "Grey"; BucketProlink bucket = bucketMap.get(buckeName); if (bucket == null) { bucket = new BucketProlink(); bucket.setType(buckeName); List bucketFieldses = new ArrayList(); BucketFields bucketFields = new BucketFields(); bucketFields.setName("availableQty"); bucketFields.setValue(String.valueOf(quantityFreePaid.getAvailable().intValue())); bucketFieldses.add(bucketFields); BucketFields bucketFieldsDispQty = new BucketFields(); bucketFieldsDispQty.setName("displayQty"); if (quantityFreePaid.getAvailable().compareTo(new BigDecimal("99")) > 0) bucketFieldsDispQty.setValue("99+"); else bucketFieldsDispQty.setValue(String.valueOf(quantityFreePaid.getAvailable().intValue())); bucketFieldses.add(bucketFieldsDispQty); bucket.setFields(bucketFieldses); bucketMap.put(buckeName, bucket); bucketQuantity.getBuckets().add(bucket); createBucketDetailsBySite(quantityFreePaid, bucket, availabilityServiceContextV4); }else{//update the bucket BigDecimal bigDecimalAgg = new BigDecimal(0.0); List bucketFieldses = bucket.getFields(); for (BucketFields bucketFields : bucketFieldses) { if (bucketFields.getName().compareToIgnoreCase("availableQty") == 0) { bigDecimalAgg = quantityFreePaid.getAvailable().add(new BigDecimal(bucketFields.getValue())); bucketFields.setValue(String.valueOf(bigDecimalAgg.intValue())); } }//done with aggregation update for (BucketFields bucketFields : bucketFieldses) { if (bucketFields.getName().compareToIgnoreCase("displayQty")== 0) { if (bigDecimalAgg.compareTo(new BigDecimal("99")) > 0) bucketFields.setValue("99+"); else bucketFields.setValue(String.valueOf(bigDecimalAgg.intValue())); break; } } updateBucketDetailsBySite(quantityFreePaid,bucket, availabilityServiceContextV4); } } } private void createorUpdateBlackBucket( Delivery delivery, AvailabilityServiceContextV4 availabilityServiceContextV4, Map bucketMap, QuantityFreePaid quantityFreePaid , BucketQuantityProlink bucketQuantity ){ ZonedDateTime bucketCutoffTime = availabilityServiceContextV4.parseDateTime(delivery.getCutOffDateTime(), false); ZonedDateTime expectedMaxDeliver = null; if (delivery.getDeliveryEstimate().getExpectationRangeMaxDeliver()!=null) { expectedMaxDeliver = availabilityServiceContextV4.parseDateTime(delivery.getDeliveryEstimate().getExpectationRangeMaxDeliver(), false); } ZonedDateTime expectedMinDeliver = null; if (delivery.getDeliveryEstimate().getExpectationRangeMinDeliver()!=null) { expectedMinDeliver = availabilityServiceContextV4.parseDateTime(delivery.getDeliveryEstimate().getExpectationRangeMinDeliver(), false); } String buckeName = "Black"; BucketProlink bucket = bucketMap.get(buckeName); if (bucket == null) { bucket = new BucketProlink(); bucket.setType(buckeName); bucket.setBucketCutoffTime(bucketCutoffTime); List bucketFieldses = new ArrayList(); BucketFields bucketFields = new BucketFields(); bucketFields.setName("availableQty"); bucketFields.setValue(String.valueOf(quantityFreePaid.getAvailable().intValue())); bucketFieldses.add(bucketFields); BucketFields bucketFieldsDispQty = new BucketFields(); bucketFieldsDispQty.setName("displayQty"); if (quantityFreePaid.getAvailable().compareTo(new BigDecimal("99")) > 0) bucketFieldsDispQty.setValue("99+"); else bucketFieldsDispQty.setValue(String.valueOf(quantityFreePaid.getAvailable().intValue())); bucketFieldses.add(bucketFieldsDispQty); BucketFields bucketFieldsCutoff = new BucketFields(); bucketFieldsCutoff.setName("cuttoffDateTime"); bucketFieldsCutoff.setValue(availabilityServiceContextV4.calculateTimeBasedOnOffset(bucketCutoffTime, 0)); bucket.setBucketCutoffTime(bucketCutoffTime); bucketFieldses.add(bucketFieldsCutoff); if (expectedMaxDeliver!=null) { BucketFields bucketFieldsDeliver = new BucketFields(); bucketFieldsDeliver.setName("deliverDateTimeMax"); bucketFieldsDeliver.setValue(delivery.getDeliveryEstimate().getExpectationRangeMaxDeliver()); bucket.setExpectedMaxDeliver(expectedMaxDeliver); bucketFieldses.add(bucketFieldsDeliver); } if (expectedMinDeliver!=null) { BucketFields bucketFieldsDeliverMin = new BucketFields(); bucketFieldsDeliverMin.setName("deliverDateTimeMin"); bucketFieldsDeliverMin.setValue(delivery.getDeliveryEstimate().getExpectationRangeMinDeliver()); bucket.setExpectedMinDeliver(expectedMinDeliver); bucketFieldses.add(bucketFieldsDeliverMin); } bucket.setFields(bucketFieldses); bucketMap.put(buckeName, bucket); bucketQuantity.getBuckets().add(bucket); //create bucket details if (availabilityServiceContextV4.getRequest().getActionRequest().getAction().getNeedBucketDetails()) createBucketDetailsBySite(quantityFreePaid,bucket, availabilityServiceContextV4); }else {//bucket exists List bucketFieldses = bucket.getFields(); BigDecimal bigDecimalAgg = new BigDecimal(0.0); for (BucketFields bucketFields : bucketFieldses) { if (bucketFields.getName().compareToIgnoreCase("availableQty") == 0) { bigDecimalAgg = quantityFreePaid.getAvailable().add(new BigDecimal(bucketFields.getValue())); bucketFields.setValue(String.valueOf(bigDecimalAgg.intValue())); } if (bucketFields.getName().compareToIgnoreCase("cuttoffDateTime") == 0) { //change it if needed to if (bucketCutoffTime.isBefore(bucket.getBucketCutoffTime())) { bucket.setBucketCutoffTime(bucketCutoffTime); bucketFields.setValue(availabilityServiceContextV4.calculateTimeBasedOnOffset(bucketCutoffTime, 0)); } } //change it if needed to if (bucketFields.getName().compareToIgnoreCase("deliverDateTimeMax") == 0) { if (bucket.getExpectedMaxDeliver()!=null && expectedMaxDeliver.isAfter(bucket.getExpectedMaxDeliver())) { bucket.setExpectedMaxDeliver(expectedMaxDeliver); bucketFields.setValue(delivery.getDeliveryEstimate().getExpectationRangeMaxDeliver()); } } if (bucketFields.getName().compareToIgnoreCase("deliverDateTimeMin") == 0) { if (bucket.getExpectedMinDeliver() !=null && expectedMinDeliver.isBefore(bucket.getExpectedMinDeliver())) { bucket.setExpectedMinDeliver(expectedMinDeliver); bucketFields.setValue(delivery.getDeliveryEstimate().getExpectationRangeMinDeliver()); } } } for (BucketFields bucketFields : bucketFieldses) { if (bucketFields.getName().compareToIgnoreCase("displayQty") == 0) { if (bigDecimalAgg.compareTo(new BigDecimal("99")) > 0) bucketFields.setValue("99+"); else bucketFields.setValue(String.valueOf(bigDecimalAgg.intValue())); break; } } //create bucket details if (availabilityServiceContextV4.getRequest().getActionRequest().getAction().getNeedBucketDetails()) updateBucketDetailsBySite(quantityFreePaid,bucket, availabilityServiceContextV4); } } private void insertIntoTomorrowOrPlus2(Delivery delivery, AvailabilityServiceContextV4 availabilityServiceContextV4, Map bucketMap, QuantityFreePaid quantityFreePaid, BucketQuantityProlink bucketQuantity){ //its after store close. so could be tomorrow ot plus2 bucket //check for tomorrow cutoff offset if (availabilityServiceContextV4.getTomorrowTime()!=null){//can have two tomorrow subbuckets //can be in tomorrows bucket only if store is open tomorrow if (availabilityServiceContextV4.getTomorrow1CutoffTime() !=null && delivery.getDeliveryEstimate().getQuickestExpectationOfAllMin().isBefore(availabilityServiceContextV4.getTomorrow1CutoffTime().withZoneSameLocal(ZoneOffset.of(availabilityServiceContextV4.getStoreTimeZone())))){ createOrUpdateTodayTomorrowBucket(delivery, "Tomorrow1",bucketMap, quantityFreePaid, availabilityServiceContextV4, bucketQuantity); return; }else{ //check if store is open tomorrow to be able to add to tomorrow2 if (availabilityServiceContextV4.getStoreCloseTomorrow()!=null && delivery.getDeliveryEstimate().getQuickestExpectationOfAllMin().isBefore(availabilityServiceContextV4.getStoreCloseTomorrow().withZoneSameLocal(ZoneOffset.of(availabilityServiceContextV4.getStoreTimeZone())))){ createOrUpdateTodayTomorrowBucket(delivery, "Tomorrow2",bucketMap, quantityFreePaid, availabilityServiceContextV4, bucketQuantity); return; }else{//goes into plus2 createOrUpdateTodayTomorrowBucket(delivery, "Blue",bucketMap, quantityFreePaid, availabilityServiceContextV4, bucketQuantity); return; } } }else{//can have only tomorrow bucket if (availabilityServiceContextV4.getStoreCloseTomorrow()!=null && delivery.getDeliveryEstimate().getQuickestExpectationOfAllMin().isAfter(availabilityServiceContextV4.getStoreOpenTomorrow().withZoneSameLocal(ZoneOffset.of(availabilityServiceContextV4.getStoreTimeZone()))) && delivery.getDeliveryEstimate().getQuickestExpectationOfAllMin().isBefore(availabilityServiceContextV4.getStoreCloseTomorrow().withZoneSameLocal(ZoneOffset.of(availabilityServiceContextV4.getStoreTimeZone())))){ createOrUpdateTodayTomorrowBucket(delivery, "Tomorrow",bucketMap, quantityFreePaid, availabilityServiceContextV4, bucketQuantity); return; }else{//goes into plus2days createOrUpdateTodayTomorrowBucket(delivery, "Blue",bucketMap, quantityFreePaid, availabilityServiceContextV4, bucketQuantity); return; } } } private void updateBucketDetailsBySite(QuantityFreePaid quantityFreePaid, BucketProlink bucket, AvailabilityServiceContextV4 availabilityServiceContextV4){ BucketDetailsProlink bucketDetailsProlink = bucket.getBucketDetailsProlink(); List bucketDetailsSitesList = bucketDetailsProlink.getSites(); BucketDetailsSite bucketDetailsSite = new BucketDetailsSite();//have to create a new one for each site. bucketDetailsSitesList.add(bucketDetailsSite); List bucketDetailsFieldses = new ArrayList();//create the details list //add available quantity BucketFields bucketDetailsFields = new BucketFields(); bucketDetailsFields.setName("availableQty"); bucketDetailsFields.setValue(String.valueOf(quantityFreePaid.getAvailable().intValue())); bucketDetailsFieldses.add(bucketDetailsFields); BucketFields bucketDetailsFieldssiteType = new BucketFields(); bucketDetailsFieldssiteType.setName("siteType"); bucketDetailsFieldssiteType.setValue(nSightCache.getSiteIdToSiteMap().get(quantityFreePaid.getSiteUUID()).getSiteType()); bucketDetailsFieldses.add(bucketDetailsFieldssiteType); if (nSightCache.getSiteIdToSiteMap().get(quantityFreePaid.getSiteUUID()).getDisplayName()!=null) { BucketFields bucketDetailsFieldssiteDisplay = new BucketFields(); bucketDetailsFieldssiteDisplay.setName("siteDisplayName"); bucketDetailsFieldssiteDisplay.setValue(nSightCache.getSiteIdToSiteMap().get(quantityFreePaid.getSiteUUID()).getDisplayName()); bucketDetailsFieldses.add(bucketDetailsFieldssiteDisplay); } // need to add additional fields for today tomorrow and blue List deliveryList = availabilityServiceContextV4.getDeliveryBySiteSorted().get(quantityFreePaid.getSiteUUID()); if (deliveryList != null && deliveryList.size() > 0) { for (Delivery delivery : deliveryList) {//iterate deliveries // need this for today, tomorrow, blue buckets if (delivery.isFreeDelivery() && delivery.isQuickestOption() && (bucket.getType().contains("Today") || bucket.getType().contains("Tomorrow") || bucket.getType().contains("Blue") )){ //this is the quickest free delivery BucketFields bucketDetailsFieldssitequickestfreeCutoff = new BucketFields(); bucketDetailsFieldssitequickestfreeCutoff.setName("quickestFreeDeliverFromStoreCutoff"); bucketDetailsFieldssitequickestfreeCutoff.setValue(delivery.getCutOffDateTime()); bucketDetailsFieldses.add(bucketDetailsFieldssitequickestfreeCutoff); if (delivery.getDeliveryEstimate().getExpectationRangeMinDeliver()!= null && delivery.getDeliveryEstimate().getExpectationRangeMinDeliver().length() > 0) { BucketFields bucketDetailsFieldssitequickestfreeExp = new BucketFields(); bucketDetailsFieldssitequickestfreeExp.setName("quickestFreeDeliverFromStoreExpectation"); bucketDetailsFieldssitequickestfreeExp.setValue(delivery.getDeliveryEstimate().getExpectationRangeMinDeliver()); bucketDetailsFieldses.add(bucketDetailsFieldssitequickestfreeExp); } } // need this for Black bucket if (!delivery.isFreeDelivery() && delivery.isQuickestOption() && (bucket.getType().contains("Black") || bucket.getType().contains("Today") || bucket.getType().contains("Tomorrow") || bucket.getType().contains("Blue"))){ //this is the quickest paid delivery BucketFields bucketDetailsFieldssitequickestpaidCutoff = new BucketFields(); bucketDetailsFieldssitequickestpaidCutoff.setName("quickestPaidDeliverFromStoreCutoff"); bucketDetailsFieldssitequickestpaidCutoff.setValue(delivery.getCutOffDateTime()); bucketDetailsFieldses.add(bucketDetailsFieldssitequickestpaidCutoff); if (delivery.getDeliveryEstimate().getExpectationRangeMinDeliver()!=null && delivery.getDeliveryEstimate().getExpectationRangeMinDeliver().length() > 0) { BucketFields bucketDetailsFieldssitequickestpaidExp = new BucketFields(); bucketDetailsFieldssitequickestpaidExp.setName("quickestPaidDeliverFromStoreExpectation"); bucketDetailsFieldssitequickestpaidExp.setValue(delivery.getDeliveryEstimate().getExpectationRangeMinDeliver()); bucketDetailsFieldses.add(bucketDetailsFieldssitequickestpaidExp); } } } } bucketDetailsSite.setFields(bucketDetailsFieldses); } private void createBucketDetailsBySite(QuantityFreePaid quantityFreePaid, BucketProlink bucket, AvailabilityServiceContextV4 availabilityServiceContextV4){ BucketDetailsProlink bucketDetailsProlink = new BucketDetailsProlink();//have to create a new Details section List bucketDetailsSitesList = new ArrayList<>(); BucketDetailsSite bucketDetailsSite = new BucketDetailsSite();//have to create a new one for each site. bucketDetailsSitesList.add(bucketDetailsSite); List bucketDetailsFieldses = new ArrayList();//create the details list bucketDetailsSite.setFields(bucketDetailsFieldses); //add available quantity BucketFields bucketDetailsFields = new BucketFields(); bucketDetailsFields.setName("availableQty"); bucketDetailsFields.setValue(String.valueOf(quantityFreePaid.getAvailable().intValue())); bucketDetailsFieldses.add(bucketDetailsFields); BucketFields bucketDetailsFieldssiteType = new BucketFields(); bucketDetailsFieldssiteType.setName("siteType"); bucketDetailsFieldssiteType.setValue(nSightCache.getSiteIdToSiteMap().get(quantityFreePaid.getSiteUUID()).getSiteType()); bucketDetailsFieldses.add(bucketDetailsFieldssiteType); if (nSightCache.getSiteIdToSiteMap().get(quantityFreePaid.getSiteUUID()).getDisplayName()!=null){ BucketFields bucketDetailsFieldssiteDisplay = new BucketFields(); bucketDetailsFieldssiteDisplay.setName("siteDisplayName"); bucketDetailsFieldssiteDisplay.setValue(nSightCache.getSiteIdToSiteMap().get(quantityFreePaid.getSiteUUID()).getDisplayName()); bucketDetailsFieldses.add(bucketDetailsFieldssiteDisplay); } // need to add additional fields for today tomorrow and blue List deliveryList = availabilityServiceContextV4.getDeliveryBySiteSorted().get(quantityFreePaid.getSiteUUID()); if (deliveryList != null && deliveryList.size() > 0) { for (Delivery delivery : deliveryList) {//iterate deliveries //this is for blue, today and tomorrow buckets if (delivery.isFreeDelivery() && delivery.isQuickestOption() && (bucket.getType().contains("Today") || bucket.getType().contains("Tomorrow") || bucket.getType().contains("Blue") )){ //this is the quickest free delivery BucketFields bucketDetailsFieldssitequickestfreeCutoff = new BucketFields(); bucketDetailsFieldssitequickestfreeCutoff.setName("quickestFreeDeliverFromStoreCutoff"); bucketDetailsFieldssitequickestfreeCutoff.setValue(delivery.getCutOffDateTime()); bucketDetailsFieldses.add(bucketDetailsFieldssitequickestfreeCutoff); if (delivery.getDeliveryEstimate().getExpectationRangeMinDeliver()!=null && delivery.getDeliveryEstimate().getExpectationRangeMinDeliver().length() > 0) { BucketFields bucketDetailsFieldssitequickestfreeExp = new BucketFields(); bucketDetailsFieldssitequickestfreeExp.setName("quickestFreeDeliverFromStoreExpectation"); bucketDetailsFieldssitequickestfreeExp.setValue(delivery.getDeliveryEstimate().getExpectationRangeMinDeliver()); bucketDetailsFieldses.add(bucketDetailsFieldssitequickestfreeExp); } } //for black bucket if (!delivery.isFreeDelivery() && delivery.isQuickestOption() && (bucket.getType().contains("Black") || bucket.getType().contains("Today") || bucket.getType().contains("Tomorrow") || bucket.getType().contains("Blue") )){ //this is the quickest free delivery BucketFields bucketDetailsFieldssitequickestpaidCutoff = new BucketFields(); bucketDetailsFieldssitequickestpaidCutoff.setName("quickestPaidDeliverFromStoreCutoff"); bucketDetailsFieldssitequickestpaidCutoff.setValue(delivery.getCutOffDateTime()); bucketDetailsFieldses.add(bucketDetailsFieldssitequickestpaidCutoff); if (delivery.getDeliveryEstimate().getExpectationRangeMinDeliver()!=null && delivery.getDeliveryEstimate().getExpectationRangeMinDeliver().length() > 0) { BucketFields bucketDetailsFieldssitequickestpaidExp = new BucketFields(); bucketDetailsFieldssitequickestpaidExp.setName("quickestPaidDeliverFromStoreExpectation"); bucketDetailsFieldssitequickestpaidExp.setValue(delivery.getDeliveryEstimate().getExpectationRangeMinDeliver()); bucketDetailsFieldses.add(bucketDetailsFieldssitequickestpaidExp); } } } } bucketDetailsProlink.setSites(bucketDetailsSitesList); bucket.setBucketDetailsProlink(bucketDetailsProlink); } private boolean isPaidOptionAvailable(String currentSiteID, AvailabilityServiceContextV4 availabilityServiceContextV4){ boolean paidAvailable = false; List deliveryList = availabilityServiceContextV4.getDeliveryBySiteSorted().get(currentSiteID); if (deliveryList != null && deliveryList.size() > 0) {// has deliveries. ideally we should be interested in only the first one for (Delivery delivery : deliveryList) {//iterate deliveries if (!delivery.isFreeDelivery()){ paidAvailable=true; break; } } } return paidAvailable; } private void createOrUpdateTodayTomorrowBucket(Delivery delivery, String bucketName, Map bucketMap, QuantityFreePaid quantityFreePaid, AvailabilityServiceContextV4 availabilityServiceContextV4 ,BucketQuantityProlink bucketQuantity){ //this is a local store. if bucket does not exist create it BucketProlink bucket = bucketMap.get(bucketName); ZonedDateTime expectedMax = availabilityServiceContextV4.parseDateTime(delivery.getDeliveryEstimate().getExpectationRangeMax(), false); ZonedDateTime expectedMin =availabilityServiceContextV4.parseDateTime(delivery.getDeliveryEstimate().getExpectationRangeMin(), false); ZonedDateTime bucketCutoffTime = availabilityServiceContextV4.parseDateTime(delivery.getCutOffDateTime(), false); ZonedDateTime expectedMaxDeliver = null; if (delivery.getDeliveryEstimate().getExpectationRangeMaxDeliver()!=null) { expectedMaxDeliver = availabilityServiceContextV4.parseDateTime(delivery.getDeliveryEstimate().getExpectationRangeMaxDeliver(), false); } ZonedDateTime expectedMinDeliver = null; if (delivery.getDeliveryEstimate().getExpectationRangeMinDeliver()!=null) { expectedMinDeliver = availabilityServiceContextV4.parseDateTime(delivery.getDeliveryEstimate().getExpectationRangeMinDeliver(), false); } if (bucket==null){//doesnt exist bucket= new BucketProlink(); bucket.setType(bucketName); bucket.setBucketCutoffTime(bucketCutoffTime); bucket.setExpectedMax(expectedMax); bucket.setExpectedMin(expectedMin); if (expectedMaxDeliver!=null) bucket.setExpectedMaxDeliver(expectedMaxDeliver); if (expectedMinDeliver!=null) bucket.setExpectedMinDeliver(expectedMinDeliver); //first create the list for the fields List bucketFieldses = new ArrayList(); //now create the fields for the bucket BucketFields bucketFields = new BucketFields(); bucketFields.setName("availableQty"); bucketFields.setValue(String.valueOf(quantityFreePaid.getAvailable().intValue())); bucketFieldses.add(bucketFields); BucketFields bucketFieldsDispQty = new BucketFields(); bucketFieldsDispQty.setName("displayQty"); if (quantityFreePaid.getAvailable().compareTo(new BigDecimal("99")) > 0) bucketFieldsDispQty.setValue("99+"); else bucketFieldsDispQty.setValue(String.valueOf(quantityFreePaid.getAvailable().intValue())); bucketFieldses.add(bucketFieldsDispQty); BucketFields bucketFieldsCutoff = new BucketFields(); bucketFieldsCutoff.setName("cuttoffDateTime"); bucket.setBucketCutoffTime(bucketCutoffTime); bucketFieldsCutoff.setValue(delivery.getCutOffDateTime()); bucketFieldses.add(bucketFieldsCutoff); if (expectedMaxDeliver!=null) { BucketFields bucketFieldsDeliver = new BucketFields(); bucketFieldsDeliver.setName("deliverDateTimeMax"); bucketFieldsDeliver.setValue(delivery.getDeliveryEstimate().getExpectationRangeMaxDeliver()); bucketFieldses.add(bucketFieldsDeliver); } if (bucketName.compareToIgnoreCase("Blue")==0 || bucketName.compareToIgnoreCase("Black")==0 || bucketName.contains("Tomorrow") || bucketName.contains("Today")){//plus 2 days if (expectedMinDeliver!=null) { BucketFields bucketFieldsdeliverDateTimeMin = new BucketFields(); bucketFieldsdeliverDateTimeMin.setName("deliverDateTimeMin"); bucketFieldsdeliverDateTimeMin.setValue(delivery.getDeliveryEstimate().getExpectationRangeMinDeliver()); bucketFieldses.add(bucketFieldsdeliverDateTimeMin); } // need to also indicate that paid options are available for this site //does this site have a paid option? if (bucketName.compareToIgnoreCase("Blue")==0) { boolean hasPaid = isPaidOptionAvailable(quantityFreePaid.getSiteUUID(), availabilityServiceContextV4); if (hasPaid) { BucketFields bucketFieldsPaid = new BucketFields(); bucketFieldsPaid.setName("paidOptionsAvailable"); bucketFieldsPaid.setValue("true"); bucketFieldses.add(bucketFieldsPaid); bucket.setHasPaidOption(true); } } } //once the fields are populated, we also need to populate the Buckets details if (availabilityServiceContextV4.getRequest().getActionRequest().getAction().getNeedBucketDetails()){ createBucketDetailsBySite(quantityFreePaid,bucket,availabilityServiceContextV4); } //set the list to the bucket bucket.setFields(bucketFieldses); bucketMap.put(bucketName, bucket); bucketQuantity.getBuckets().add(bucket); }else{//bucket exists //just have to add this to the available and aggregate List bucketFieldses = bucket.getFields(); BigDecimal bigDecimalAgg = new BigDecimal(0.0); if (bucketName.compareToIgnoreCase("Blue")==0) {//plus 2 days //should the deliverdatetimes change? if (!bucket.isHasPaidOption()){ boolean hasPaid = isPaidOptionAvailable(quantityFreePaid.getSiteUUID(), availabilityServiceContextV4); if(hasPaid){ BucketFields bucketFieldsPaid = new BucketFields(); bucketFieldsPaid.setName("paidOptionsAvailable"); bucketFieldsPaid.setValue("true"); bucketFieldses.add(bucketFieldsPaid); } } } // we will have to iterate once again seperately for getting the display qty for ( BucketFields bucketFields : bucketFieldses){ if (bucketFields.getName().compareToIgnoreCase("availableQty")== 0){ BigDecimal bigDecimal = quantityFreePaid.getAvailable().add(new BigDecimal(bucketFields.getValue())); bucketFields.setValue(String.valueOf(bigDecimal.intValue())); bigDecimalAgg = bigDecimal; } //also need to update the times if we find a better range if (bucketFields.getName().compareToIgnoreCase("cuttoffDateTime")== 0){ //change it if needed to if (bucketCutoffTime.isBefore(bucket.getBucketCutoffTime())){ bucket.setBucketCutoffTime(bucketCutoffTime); bucketFields.setValue(availabilityServiceContextV4.calculateTimeBasedOnOffset(bucketCutoffTime, 0)); } } if (bucketFields.getName().compareToIgnoreCase("deliverDateTimeMax")== 0){ //change it if needed to if (bucket.getExpectedMaxDeliver() != null && expectedMaxDeliver.isAfter(bucket.getExpectedMaxDeliver())){ bucket.setExpectedMaxDeliver(expectedMaxDeliver); bucketFields.setValue(delivery.getDeliveryEstimate().getExpectationRangeMaxDeliver()); } } if (bucketFields.getName().compareToIgnoreCase("deliverDateTimeMin")== 0 && (bucketName.compareToIgnoreCase("Blue")==0 || bucketName.compareToIgnoreCase("Black")==0 || bucketName.contains("Tomorrow") || bucketName.contains("Today"))){ //change it if needed to if (bucket.getExpectedMinDeliver() !=null &&expectedMinDeliver.isBefore(bucket.getExpectedMinDeliver())){ bucket.setExpectedMinDeliver(expectedMinDeliver); bucketFields.setValue(delivery.getDeliveryEstimate().getExpectationRangeMinDeliver()); } } } //now iterate just to populate the Display Qty since we would have aggregated in previous loop for ( BucketFields bucketFields : bucketFieldses) { if (bucketFields.getName().compareToIgnoreCase("displayQty")== 0) { if (bigDecimalAgg.compareTo(new BigDecimal("99")) > 0) bucketFields.setValue("99+"); else bucketFields.setValue(String.valueOf(bigDecimalAgg.intValue())); break; } } //once the core fields are populated, we also need to update the Buckets details fields if (availabilityServiceContextV4.getRequest().getActionRequest().getAction().getNeedBucketDetails()){ updateBucketDetailsBySite(quantityFreePaid,bucket, availabilityServiceContextV4); } } } public void createLocalBucket( Map bucketMap, QuantityFreePaid quantityFreePaid, AvailabilityServiceContextV4 availabilityServiceContextV4 ,BucketQuantityProlink bucketQuantity){ //this is a local store. if bucket does not exist create it //main counter primary DC and local store will contribute to this nucket BucketProlink bucket = bucketMap.get("Local Store"); if (bucket==null){ bucket= new BucketProlink(); bucket.setType("Local Store"); //first create the list for the fields List bucketFieldses = new ArrayList(); //now create the fields for the bucket BucketFields bucketFields = new BucketFields(); bucketFields.setName("availableQty"); bucketFields.setValue(String.valueOf(quantityFreePaid.getAvailable().intValue())); bucketFieldses.add(bucketFields); BucketFields bucketFieldsDispQty = new BucketFields(); bucketFieldsDispQty.setName("displayQty"); if (quantityFreePaid.getAvailable().compareTo(new BigDecimal("99")) > 0) bucketFieldsDispQty.setValue("99+"); else bucketFieldsDispQty.setValue(String.valueOf(quantityFreePaid.getAvailable().intValue())); bucketFieldses.add(bucketFieldsDispQty); //local bucket times are based on if we are within store hours or next store open BucketFields bucketFieldsDeliver = new BucketFields(); bucketFieldsDeliver.setName("deliverDateTime"); bucketFieldsDeliver.setValue(availabilityServiceContextV4.calculateLocalTimeBasedOnTime(availabilityServiceContextV4.getStoreOpen(), availabilityServiceContextV4.getDeliverFromStoreOffset())); bucketFieldses.add(bucketFieldsDeliver); //once the fields are populated, we also need to populate the Buckets details if (availabilityServiceContextV4.getRequest().getActionRequest().getAction().getNeedBucketDetails()){ createBucketDetailsBySite(quantityFreePaid,bucket, availabilityServiceContextV4); } //set the list to the bucket bucket.setFields(bucketFieldses); bucketMap.put("Local Store", bucket); bucketQuantity.getBuckets().add(bucket); }else{ /// if its a main counter we could have got an update //just have to add this to the available and aggregate List bucketFieldses = bucket.getFields(); BigDecimal bigDecimalAgg = new BigDecimal(0.0); for ( BucketFields bucketFields : bucketFieldses) { if (bucketFields.getName().compareToIgnoreCase("availableQty") == 0) { BigDecimal bigDecimal = quantityFreePaid.getAvailable().add(new BigDecimal(bucketFields.getValue())); bigDecimalAgg = bigDecimal; bucketFields.setValue(String.valueOf(bigDecimal.intValue())); } if (bucketFields.getName().compareToIgnoreCase("displayQty")== 0) { if (bigDecimalAgg.compareTo(new BigDecimal("99")) > 0) bucketFields.setValue("99+"); else bucketFields.setValue(String.valueOf(bigDecimalAgg.intValue())); } } //once the core fields are populated, we also need to update the Buckets details fields if (availabilityServiceContextV4.getRequest().getActionRequest().getAction().getNeedBucketDetails()){ updateBucketDetailsBySite(quantityFreePaid,bucket, availabilityServiceContextV4); } } } }