package com.genpt.nsight.v4.service.impl; import com.datastax.driver.core.*; import com.genpt.nsight.NSightCache; import com.genpt.nsight.config.DeliveryTypes; import com.genpt.nsight.config.NSightProperties; import com.genpt.nsight.v1.model.DeliveryDestination; import com.genpt.nsight.v1.model.DeliveryEstimate; import com.genpt.nsight.v1.model.JavaDeepClone; import com.genpt.nsight.v1.model.LeadTimes; import com.genpt.nsight.v1.model.serializer.DeliveryCutOffSerializer; import com.genpt.nsight.v2.SplunkLogger; import com.genpt.nsight.v4.AvailabilityServiceContextV4; import com.genpt.nsight.v4.service.Site2ZipDeliveryEstimateServiceV4; import com.google.common.util.concurrent.Futures; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.temporal.ChronoUnit; import java.util.*; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; @Service("Site2ZipDeliveryEstimateServiceV4") public class Site2ZipDeliveryEstimateServiceV4Impl implements Site2ZipDeliveryEstimateServiceV4 { private String[] dayOfWeekColNames = new String[]{"monday_cutoff_time", "tuesday_cutoff_time", "wednesday_cutoff_time", "thursday_cutoff_time", "friday_cutoff_time", "saturday_cutoff_time", "sunday_cutoff_time"}; private String[] leadTimesDayOfWeekColNames = new String[]{"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"}; private static final Logger LOGGER = LoggerFactory.getLogger(Site2ZipDeliveryEstimateServiceV4Impl.class); @Autowired DeliveryTypes deliveryTypes; @Autowired private Session session; @Autowired NSightCache nSightCache; PreparedStatement deliveryEstimatePS; @Autowired NSightProperties nSightProperties; @PostConstruct public void init() { deliveryEstimatePS = session.prepare("SELECT delivery_service_zone, ship_to_zip_code, delivery_service_type, ship_from_site_identifier, monday_cutoff_time, tuesday_cutoff_time, wednesday_cutoff_time, thursday_cutoff_time, friday_cutoff_time, saturday_cutoff_time, sunday_cutoff_time, service_duration_designator, service_duration_max_value, service_duration_min_value FROM site_to_zip_delivery_matrix where ship_to_zip_code = ? and delivery_service_type = ? and ship_from_site_identifier in ?;"); deliveryEstimatePS.setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM); } @Override public ResultSetFuture getDeliveryEstimates(UUID toSiteId, String zipcode, String deliveryType, List fromSiteList) { BoundStatement boundStatement = deliveryEstimatePS.bind(zipcode.trim(),deliveryType,fromSiteList); return session.executeAsync(boundStatement); } @Override public void setDeliveryEstimateFutures(AvailabilityServiceContextV4 availabilityServiceContextV3) { if (availabilityServiceContextV3.getRequest().getDetailRequest().getInventoryRelationshipsRequested().isServingDC()) availabilityServiceContextV3.getFromSiteIds().add(availabilityServiceContextV3.getPrimaryDC().getSiteId()); if (availabilityServiceContextV3.getRequest().getDetailRequest().getInventoryRelationshipsRequested().isAllOtherDCs()) availabilityServiceContextV3.getFromSiteIds().addAll(nSightCache.getDcSet()); if (availabilityServiceContextV3.getRequest().getDetailRequest().getInventoryRelationshipsRequested().isAllSuppliers()) availabilityServiceContextV3.getFromSiteIds().addAll(nSightCache.getSupplierIdSet()); List fromSiteIdList = new ArrayList<>(availabilityServiceContextV3.getFromSiteIds().size()); availabilityServiceContextV3.getFromSiteIds().forEach(siteId -> fromSiteIdList.add(UUID.fromString(siteId))); UUID fromSiteId = UUID.fromString(availabilityServiceContextV3.getRequestingSite().getSiteIdentifier()); List deliveryTimeFutureResultSetList = new ArrayList<>(); //get deliver types by the full zipcode for (String zipcode : availabilityServiceContextV3.getZipCodesSet()) { deliveryTypes.getDeliveryTypes().stream().map(deliveryType -> { return getDeliveryEstimates(fromSiteId, zipcode, deliveryType, fromSiteIdList); }).forEach(deliveryTimeFutureResultSetList::add); } Set zoneSet = new HashSet<>(); //get deliver types by the zone only if the zipcode is greater than 3 for (String zipcode : availabilityServiceContextV3.getZipCodesSet()) { deliveryTypes.getDeliveryTypes().stream().map(deliveryType -> { String zone = zipcode.substring(0, 3) + deliveryType;//key will be 3 digit zip and rawDelivery type if (!zoneSet.contains(zone)) {//doest have the zone, add it zoneSet.add(zone); return getDeliveryEstimates(fromSiteId, zipcode.substring(0, 3), deliveryType, fromSiteIdList); } else { return null; } }).forEach(deliveryTimeFutureResultSetList::add); } //remove any nulls that we would have added deliveryTimeFutureResultSetList.removeIf(Objects::isNull); //add the futures to the S2Z calls list in the context if (availabilityServiceContextV3.getDeliveryZipEstimateFutures()==null) { availabilityServiceContextV3.setDeliveryZipEstimateFutures(new ArrayList<>()); availabilityServiceContextV3.getDeliveryZipEstimateFutures().addAll(Futures.inCompletionOrder(deliveryTimeFutureResultSetList)); }else availabilityServiceContextV3.getDeliveryZipEstimateFutures().addAll(Futures.inCompletionOrder(deliveryTimeFutureResultSetList)); } private com.genpt.nsight.v4.model.RawDelivery createDelivery(String serviceDurationDesignator,Row row, AvailabilityServiceContextV4 availabilityServiceContextV3, List rawDeliveryList, Set fromSitesToZip){ com.genpt.nsight.v4.model.RawDelivery rawDelivery =null; if (serviceDurationDesignator != null) { rawDelivery = new com.genpt.nsight.v4.model.RawDelivery(); rawDelivery.setDeliveryType(row.getString("delivery_service_type")); if (row.getColumnDefinitions().contains("delivery_service_zone")) rawDelivery.setZone(row.getString("delivery_service_zone")); String shipFrom = null; final String deliveryType = rawDelivery.getDeliveryType(); rawDelivery.setSiteId(row.getUUID("ship_from_site_identifier").toString()); shipFrom = row.getUUID("ship_from_site_identifier").toString(); String shipTo = null; if (row.getColumnDefinitions().contains("ship_to_site_identifier")) shipTo = row.getUUID("ship_to_site_identifier").toString(); String shipToZip = null; if (row.getColumnDefinitions().contains("ship_to_zip_code")) shipToZip = row.getString("ship_to_zip_code"); List deliveryCutOffList = null; for (int i = 0; i < dayOfWeekColNames.length; i++) { boolean isNull = row.isNull(dayOfWeekColNames[i]); if (!isNull) { long deliveryCutOffTime = row.getTime(dayOfWeekColNames[i]); com.genpt.nsight.v4.model.DeliveryCutOff deliveryCutOff = null; //if (deliveryCutOffTime != 0L) { deliveryCutOff = new com.genpt.nsight.v4.model.DeliveryCutOff(i, deliveryCutOffTime / 1000000L); if (deliveryCutOffList == null) { deliveryCutOffList = new ArrayList<>(); } deliveryCutOffList.add(deliveryCutOff); } } } //populate lead times if (availabilityServiceContextV3.getLeadTimeBySite() !=null && availabilityServiceContextV3.getLeadTimeBySite().containsKey(shipFrom)){ List copy = availabilityServiceContextV3.getLeadTimeBySite().get(shipFrom).stream() .filter(s -> s.getDeliveryServiceType().compareToIgnoreCase(deliveryType) == 0) .collect(Collectors.toList()); if (copy!=null & copy.size() > 0) rawDelivery.setLeadTimes(copy); } if (deliveryCutOffList != null) { rawDelivery.setDeliveryCutOff(deliveryCutOffList); } rawDelivery.setDeliveryEstimate(new DeliveryEstimate()); rawDelivery.getDeliveryEstimate().setDurationDesignator(serviceDurationDesignator); rawDelivery.getDeliveryEstimate().setDurationMinValue(row.getInt("service_duration_min_value")); rawDelivery.getDeliveryEstimate().setDurationMaxValue(row.getInt("service_duration_max_value")); DeliveryDestination deliveryDestination = new DeliveryDestination(); if (shipTo != null) {//site. need to get alias and value String aliasFullName = availabilityServiceContextV3.getReverseShipToSitesMap().get(shipTo); if (aliasFullName != null) { String arr[] = aliasFullName.split("\\|"); if (arr.length > 1) { deliveryDestination.setValue(arr[1]); deliveryDestination.setName(arr[0]); rawDelivery.setDeliveryDestination(deliveryDestination); rawDeliveryList.add(rawDelivery);//add it to the list }//valid alias names for SiteID } } if (shipToZip != null && shipToZip.length() == 5) {//zip, that means they had requested a zipcode //zipcode 5 digit deliveryDestination.setName("Zip Code"); deliveryDestination.setValue(shipToZip); rawDelivery.setDeliveryDestination(deliveryDestination); rawDeliveryList.add(rawDelivery);//add it to the list //also add it to the set which stores 5 digit deliveris fromSitesToZip.add(rawDelivery.getDeliveryType()+shipFrom+shipToZip.substring(0,3)); //System.out.println("Added zip: " + rawDelivery.getDeliveryType()+shipFrom+shipToZip.substring(0,3)); } if (shipToZip != null && shipToZip.length() == 3) {//3 digit zipcode //check if the 5 digit for this 3 digit is already present //if its present ignore the 3 digit if (fromSitesToZip.contains(rawDelivery.getDeliveryType() + shipFrom + shipToZip)) { //ignore this zipcode //System.out.println("Ignoring ZIP: "+ rawDelivery.getDeliveryType() + shipFrom + shipToZip); } else { //loop through the requested 5 digit zips for (String zipcode : availabilityServiceContextV3.getZipCodesSet()) { if (zipcode.contains(shipToZip)) { //create a new deliuvery section for this zip com.genpt.nsight.v4.model.RawDelivery altRawDelivery = (com.genpt.nsight.v4.model.RawDelivery) JavaDeepClone.deepClone(rawDelivery); DeliveryDestination deliveryAltDestination = new DeliveryDestination(); deliveryAltDestination.setName("Zip Code"); deliveryAltDestination.setValue(zipcode); altRawDelivery.setDeliveryDestination(deliveryAltDestination); if (!rawDeliveryList.contains(altRawDelivery)) rawDeliveryList.add(altRawDelivery);//add it to the list } } } } } return rawDelivery; } private boolean isDeliveryQuicker( com.genpt.nsight.v4.model.RawDelivery rawDelivery, com.genpt.nsight.v4.model.RawDelivery existingRawDelivery){ boolean quicker = false; String existingDesignator = existingRawDelivery.getDeliveryEstimate().getDurationDesignator(); String currentDesignator = existingRawDelivery.getDeliveryEstimate().getDurationDesignator(); long existCommonDenom = 0;long currentCommonDenom = 0; if (existingDesignator.compareToIgnoreCase("Days")==0)//convert to minutes existCommonDenom = existingRawDelivery.getDeliveryEstimate().getDurationMinValue() * 1440; else if (existingDesignator.compareToIgnoreCase("Hours")==0)// hours to inutes existCommonDenom = existingRawDelivery.getDeliveryEstimate().getDurationMinValue() * 60; else existCommonDenom = existingRawDelivery.getDeliveryEstimate().getDurationMinValue(); if (currentDesignator.compareToIgnoreCase("Days")==0)//convert to minutes currentCommonDenom = rawDelivery.getDeliveryEstimate().getDurationMinValue() * 1440; else if (currentDesignator.compareToIgnoreCase("Hours")==0)// hours to inutes currentCommonDenom = rawDelivery.getDeliveryEstimate().getDurationMinValue() * 60; else currentCommonDenom = rawDelivery.getDeliveryEstimate().getDurationMinValue(); if (currentCommonDenom < existCommonDenom) quicker = true; return quicker; } private void compareAndSetQuickestDeliveryList(AvailabilityServiceContextV4 availabilityServiceContextV3, Row row, List existingRawDeliveryList, String deliveryServiceType, String fromSiteID, String serviceDurationDesignator, float shipFromTZ, boolean isPaidDelivery, List existingFreeRawDeliveryList, List existingPaidRawDeliveryList){ com.genpt.nsight.v4.model.RawDelivery existingRawDelivery = existingRawDeliveryList.get(0); com.genpt.nsight.v4.model.RawDelivery existingFreeRawDelivery = existingFreeRawDeliveryList.size() > 0 ? existingFreeRawDeliveryList.get(0) : null; com.genpt.nsight.v4.model.RawDelivery existingPaidRawDelivery = existingPaidRawDeliveryList.size() > 0 ? existingPaidRawDeliveryList.get(0): null; //create the new rawDelivery com.genpt.nsight.v4.model.RawDelivery rawDelivery = new com.genpt.nsight.v4.model.RawDelivery(); rawDelivery.setDeliveryType(deliveryServiceType); if (row.getColumnDefinitions().contains("delivery_service_zone")) rawDelivery.setZone(row.getString("delivery_service_zone")); rawDelivery.setSiteId(fromSiteID); List deliveryCutOffList = null; for (int i = 0; i < 7; i++) { //check if the time is a null value boolean isNull = row.isNull(dayOfWeekColNames[(availabilityServiceContextV3.getDayOfWeekLocal() + i) % 7]); if (!isNull) { long deliveryCutOffTime = row.getTime(dayOfWeekColNames[(availabilityServiceContextV3.getDayOfWeekLocal() + i) % 7]); //include lead times in calculation String dayOfWeek = leadTimesDayOfWeekColNames[(availabilityServiceContextV3.getDayOfWeekLocal() + i) % 7]; int sumLeadTimes = availabilityServiceContextV3.getLeadTimesForSite(dayOfWeek, fromSiteID, deliveryServiceType); boolean afterCutOff = false; if (availabilityServiceContextV3.getStoreOffSetTime() != null && shipFromTZ != 0) { if (!availabilityServiceContextV3.requestTimeBeforeCutOffTime(deliveryCutOffTime/1000000, shipFromTZ,row.getInt("service_duration_min_value")+sumLeadTimes))//expects millis afterCutOff=true; }else{ long now = 1000000 * availabilityServiceContextV3.getTimeOfDay(); if (deliveryCutOffTime < now) afterCutOff=true; } //if we have passed the cutoff time if (i == 0 ) { if (afterCutOff) continue; else{//before the cutoff time for today com.genpt.nsight.v4.model.DeliveryCutOff deliveryCutOff = null; deliveryCutOff = new com.genpt.nsight.v4.model.DeliveryCutOff((availabilityServiceContextV3.getDayOfWeekLocal() + i) % 7, deliveryCutOffTime / 1000000L); if (deliveryCutOffList == null) { deliveryCutOffList = new ArrayList<>(); } deliveryCutOffList.add(deliveryCutOff); rawDelivery.setDeliveryEstimate(new DeliveryEstimate()); rawDelivery.getDeliveryEstimate().setDurationDesignator(serviceDurationDesignator); rawDelivery.getDeliveryEstimate().setDurationMinValue(row.getInt("service_duration_min_value") + i);//since i is 0 rawDelivery.getDeliveryEstimate().setDurationMaxValue(row.getInt("service_duration_max_value") + i); rawDelivery.getDeliveryEstimate().setDurationMinValueWithLeadTime(row.getInt("service_duration_min_value") + i + sumLeadTimes); rawDelivery.getDeliveryEstimate().setDurationMaxValueWithLeadTime(row.getInt("service_duration_max_value") + i + sumLeadTimes); break; } } else { com.genpt.nsight.v4.model.DeliveryCutOff deliveryCutOff = null; deliveryCutOff = new com.genpt.nsight.v4.model.DeliveryCutOff((availabilityServiceContextV3.getDayOfWeekLocal() + i) % 7, deliveryCutOffTime / 1000000L); if (deliveryCutOffList == null) { deliveryCutOffList = new ArrayList<>(); } deliveryCutOffList.add(deliveryCutOff); rawDelivery.setDeliveryEstimate(new DeliveryEstimate()); rawDelivery.getDeliveryEstimate().setDurationDesignator(serviceDurationDesignator); rawDelivery.getDeliveryEstimate().setDurationMinValue(row.getInt("service_duration_min_value") + i); rawDelivery.getDeliveryEstimate().setDurationMaxValue(row.getInt("service_duration_max_value") + i); rawDelivery.getDeliveryEstimate().setDurationMinValueWithLeadTime(row.getInt("service_duration_min_value") + i + sumLeadTimes); rawDelivery.getDeliveryEstimate().setDurationMaxValueWithLeadTime(row.getInt("service_duration_max_value") + i + sumLeadTimes); break; } } } if (deliveryCutOffList != null) rawDelivery.setDeliveryCutOff(deliveryCutOffList); //now that we are done creating the new RawDelivery Object //check which rawDelivery is quicker. if the new rawDelivery has valid values we are good if (rawDelivery.getDeliveryCutOff() != null && rawDelivery.getDeliveryCutOff().size() > 0 && rawDelivery.getDeliveryEstimate() != null) { //first check which has lower durations String existingDesignator = existingRawDelivery.getDeliveryEstimate().getDurationDesignator(); String currentDesignator = existingRawDelivery.getDeliveryEstimate().getDurationDesignator(); long existCommonDenom = 0;long currentCommonDenom = 0; if (existingDesignator.compareToIgnoreCase("Days")==0)//convert to minutes existCommonDenom = existingRawDelivery.getDeliveryEstimate().getDurationMinValue() * 1440; else if (existingDesignator.compareToIgnoreCase("Hours")==0)// hours to inutes existCommonDenom = existingRawDelivery.getDeliveryEstimate().getDurationMinValue() * 60; else existCommonDenom = existingRawDelivery.getDeliveryEstimate().getDurationMinValue(); if (currentDesignator.compareToIgnoreCase("Days")==0)//convert to minutes currentCommonDenom = rawDelivery.getDeliveryEstimate().getDurationMinValue() * 1440; else if (currentDesignator.compareToIgnoreCase("Hours")==0)// hours to inutes currentCommonDenom = rawDelivery.getDeliveryEstimate().getDurationMinValue() * 60; else currentCommonDenom = rawDelivery.getDeliveryEstimate().getDurationMinValue(); if (isDeliveryQuicker(rawDelivery, existingRawDelivery)) { // new rawDelivery is quicker //use this new rawDelivery existingRawDeliveryList.remove(0); com.genpt.nsight.v4.model.RawDelivery newRawDelivery = (com.genpt.nsight.v4.model.RawDelivery) JavaDeepClone.deepClone(rawDelivery); existingRawDeliveryList.add(newRawDelivery); } else if (currentCommonDenom == existCommonDenom) { // durations are equal // then check which which is quicker //if (rawDelivery.getDeliveryCutOff().get(0) != null && existingRawDelivery.getDeliveryCutOff().get(0) != null && rawDelivery.getDeliveryCutOff().get(0).getCutOffTime() > existingRawDelivery.getDeliveryCutOff().get(0).getCutOffTime()) { if (rawDelivery.getDeliveryCutOff().get(0) != null && existingRawDelivery.getDeliveryCutOff().get(0) != null && availabilityServiceContextV3.cutOffTimeAfterMax(rawDelivery.getDeliveryCutOff().get(0).getCutOffTime(), existingRawDelivery.getDeliveryCutOff().get(0).getCutOffTime(), shipFromTZ, shipFromTZ) ) { /// use the new one existingRawDeliveryList.remove(0); com.genpt.nsight.v4.model.RawDelivery newRawDelivery = (com.genpt.nsight.v4.model.RawDelivery) JavaDeepClone.deepClone(rawDelivery); existingRawDeliveryList.add(newRawDelivery); } } } //at this point we have the quickest rawDelivery across paid and free for this site if (existingPaidRawDelivery != null && isPaidDelivery){ if (rawDelivery.getDeliveryCutOff() != null && rawDelivery.getDeliveryCutOff().size() > 0 && rawDelivery.getDeliveryEstimate() != null) { //first check which has lower durations if (rawDelivery.getDeliveryEstimate().getDurationMinValueWithLeadTime() < existingPaidRawDelivery.getDeliveryEstimate().getDurationMinValueWithLeadTime()) { // new rawDelivery is quicker //use this rawDelivery. the old one from the list existingPaidRawDeliveryList.remove(0); com.genpt.nsight.v4.model.RawDelivery paidRawDelivery = (com.genpt.nsight.v4.model.RawDelivery) JavaDeepClone.deepClone(rawDelivery); existingPaidRawDeliveryList.add(paidRawDelivery); } else if (rawDelivery.getDeliveryEstimate().getDurationMinValueWithLeadTime() == existingPaidRawDelivery.getDeliveryEstimate().getDurationMinValueWithLeadTime()) { // durations are equal // then check which which is quicker if (rawDelivery.getDeliveryCutOff().get(0) != null && existingPaidRawDelivery.getDeliveryCutOff().get(0) != null && availabilityServiceContextV3.cutOffTimeAfterMax(rawDelivery.getDeliveryCutOff().get(0).getCutOffTime(), existingPaidRawDelivery.getDeliveryCutOff().get(0).getCutOffTime(), shipFromTZ, shipFromTZ) ) { /// use the new one existingPaidRawDeliveryList.remove(0); com.genpt.nsight.v4.model.RawDelivery paidRawDelivery = (com.genpt.nsight.v4.model.RawDelivery) JavaDeepClone.deepClone(rawDelivery); existingPaidRawDeliveryList.add(paidRawDelivery); } } } }// now we have the quickest paid rawDelivery if (existingFreeRawDelivery != null && !isPaidDelivery){ if (rawDelivery.getDeliveryCutOff() != null && rawDelivery.getDeliveryCutOff().size() > 0 && rawDelivery.getDeliveryEstimate() != null) { //first check which has lower durations if (rawDelivery.getDeliveryEstimate().getDurationMinValueWithLeadTime() < existingFreeRawDelivery.getDeliveryEstimate().getDurationMinValueWithLeadTime()) { // new rawDelivery is quicker //use this new rawDelivery. existingFreeRawDeliveryList.remove(0); com.genpt.nsight.v4.model.RawDelivery freeRawDelivery = (com.genpt.nsight.v4.model.RawDelivery) JavaDeepClone.deepClone(rawDelivery); existingFreeRawDeliveryList.add(freeRawDelivery); } else if (rawDelivery.getDeliveryEstimate().getDurationMinValueWithLeadTime() == existingFreeRawDelivery.getDeliveryEstimate().getDurationMinValueWithLeadTime()) { // durations are equal // then check which which is quicker if (rawDelivery.getDeliveryCutOff().get(0) != null && existingFreeRawDelivery.getDeliveryCutOff().get(0) != null && availabilityServiceContextV3.cutOffTimeAfterMax(rawDelivery.getDeliveryCutOff().get(0).getCutOffTime(), existingFreeRawDelivery.getDeliveryCutOff().get(0).getCutOffTime(), shipFromTZ, shipFromTZ) ) { /// use the new one existingFreeRawDeliveryList.remove(0); com.genpt.nsight.v4.model.RawDelivery freeRawDelivery = (com.genpt.nsight.v4.model.RawDelivery) JavaDeepClone.deepClone(rawDelivery); existingFreeRawDeliveryList.add(freeRawDelivery); } } } }// now we have the quickest free rawDelivery if (isPaidDelivery){ if (existingPaidRawDeliveryList.size() == 0 && rawDelivery.getDeliveryCutOff()!= null && rawDelivery.getDeliveryCutOff().size() > 0 ){ com.genpt.nsight.v4.model.RawDelivery paidRawDelivery = (com.genpt.nsight.v4.model.RawDelivery) JavaDeepClone.deepClone(rawDelivery); existingPaidRawDeliveryList.add(paidRawDelivery); } }else{ if (existingFreeRawDeliveryList.size() == 0 && rawDelivery.getDeliveryCutOff()!= null && rawDelivery.getDeliveryCutOff().size() > 0){ com.genpt.nsight.v4.model.RawDelivery freeRawDelivery = (com.genpt.nsight.v4.model.RawDelivery) JavaDeepClone.deepClone(rawDelivery); existingFreeRawDeliveryList.add(freeRawDelivery); } } } private void createFreePaidDelivery(String serviceDurationDesignator,Row row, Map> quickestFreePaidDeliveryBySite, AvailabilityServiceContextV4 availabilityServiceContextV3, Map> freeDeliveryBySite, Map> paidDeliveryBySite ){ SplunkLogger splunkLogger = new SplunkLogger(availabilityServiceContextV3.getRequest().getHeaderRequest()); if (serviceDurationDesignator != null) { List existingFreeRawDeliveryList = null; List existingPaidRawDeliveryList =null ; List existingRawDeliveryList = null; boolean isDeliveryPaid = false; String deliveryServiceType = row.getString("delivery_service_type"); if (nSightProperties.getPaidMOTS().contains(deliveryServiceType)) isDeliveryPaid=true; String fromSiteID = row.getUUID("ship_from_site_identifier").toString(); float shipFromTZ = 0;//set the timezone for the shipfrom site if (nSightCache.getSiteIdToSiteMap().get(fromSiteID) != null && nSightCache.getSiteIdToSiteMap().get(fromSiteID).getTimeZone() != null && nSightCache.getSiteIdToSiteMap().get(fromSiteID).getTimeZone().trim() != "") try { shipFromTZ = Float.parseFloat(nSightCache.getSiteIdToSiteMap().get(fromSiteID).getTimeZone()); }catch (Exception ex){ LOGGER.error(splunkLogger.toString() + " , Error in createFreePaidDelivery, Message : {}, StackTrace: {} ", ex.getMessage(), ex.getStackTrace()); } boolean noCutoffTimes = false; if (quickestFreePaidDeliveryBySite.containsKey(fromSiteID)) {// entry for this site exists in map //get the existing rawDelivery to compare with the new rawDelivery existingRawDeliveryList = quickestFreePaidDeliveryBySite.get(fromSiteID); existingFreeRawDeliveryList = freeDeliveryBySite.get(fromSiteID); existingPaidRawDeliveryList = paidDeliveryBySite.get(fromSiteID); if (existingFreeRawDeliveryList == null) existingFreeRawDeliveryList = new ArrayList<>(); if (existingPaidRawDeliveryList == null) existingPaidRawDeliveryList = new ArrayList<>(); compareAndSetQuickestDeliveryList(availabilityServiceContextV3,row, existingRawDeliveryList, deliveryServiceType,fromSiteID,serviceDurationDesignator, shipFromTZ, isDeliveryPaid, existingFreeRawDeliveryList, existingPaidRawDeliveryList); //at this point free, paid and quickest lists would be populated for this site } else { existingRawDeliveryList = new ArrayList<>(); //found the first rawDelivery com.genpt.nsight.v4.model.RawDelivery rawDelivery = new com.genpt.nsight.v4.model.RawDelivery(); rawDelivery.setDeliveryType(deliveryServiceType); if (row.getColumnDefinitions().contains("delivery_service_zone")) rawDelivery.setZone(row.getString("delivery_service_zone")); rawDelivery.setSiteId(fromSiteID); //populate lead times if (availabilityServiceContextV3.getLeadTimeBySite() !=null && availabilityServiceContextV3.getLeadTimeBySite().containsKey(fromSiteID)){ List copy = availabilityServiceContextV3.getLeadTimeBySite().get(fromSiteID).stream() .filter(s -> s.getDeliveryServiceType().compareToIgnoreCase(deliveryServiceType) == 0) .collect(Collectors.toList()); if (copy!=null & copy.size() > 0) rawDelivery.setLeadTimes(copy); } List deliveryCutOffList = null; for (int i = 0; i < 7; i++) { //check if the time is a null value boolean isNull = row.isNull(dayOfWeekColNames[(availabilityServiceContextV3.getDayOfWeekLocal() + i) % 7]); //include lead times in calculation String dayOfWeek = leadTimesDayOfWeekColNames[(availabilityServiceContextV3.getDayOfWeekLocal() + i) % 7]; int sumLeadTimes = availabilityServiceContextV3.getLeadTimesForSite(dayOfWeek, fromSiteID, deliveryServiceType); if (!isNull) { long deliveryCutOffTime = row.getTime(dayOfWeekColNames[(availabilityServiceContextV3.getDayOfWeekLocal() + i) % 7]); boolean afterCutOff = false; if (availabilityServiceContextV3.getStoreOffSetTime() != null && shipFromTZ != 0) { if (!availabilityServiceContextV3.requestTimeBeforeCutOffTime(deliveryCutOffTime/1000000, shipFromTZ,row.getInt("service_duration_min_value")+sumLeadTimes))//expects millis afterCutOff=true; }else{ long now = 1000000 * availabilityServiceContextV3.getTimeOfDay(); if (deliveryCutOffTime < now) afterCutOff=true; } //if we have passed the cutoff time if (i == 0 ) { if (afterCutOff) { continue;//passed the cutoff time for today } else{//found before the cutoff time for today com.genpt.nsight.v4.model.DeliveryCutOff deliveryCutOff = null; deliveryCutOff = new com.genpt.nsight.v4.model.DeliveryCutOff((availabilityServiceContextV3.getDayOfWeekLocal() + i) % 7, deliveryCutOffTime / 1000000L); if (deliveryCutOffList == null) { deliveryCutOffList = new ArrayList<>(); } deliveryCutOffList.add(deliveryCutOff); rawDelivery.setDeliveryEstimate(new DeliveryEstimate()); rawDelivery.getDeliveryEstimate().setDurationDesignator(serviceDurationDesignator); rawDelivery.getDeliveryEstimate().setDurationMinValue(row.getInt("service_duration_min_value") + i); rawDelivery.getDeliveryEstimate().setDurationMaxValue(row.getInt("service_duration_max_value") + i); rawDelivery.getDeliveryEstimate().setDurationMinValueWithLeadTime(row.getInt("service_duration_min_value") + i + sumLeadTimes); rawDelivery.getDeliveryEstimate().setDurationMaxValueWithLeadTime(row.getInt("service_duration_max_value") + i + sumLeadTimes); break; } } else { com.genpt.nsight.v4.model.DeliveryCutOff deliveryCutOff = null; deliveryCutOff = new com.genpt.nsight.v4.model.DeliveryCutOff((availabilityServiceContextV3.getDayOfWeekLocal() + i) % 7, deliveryCutOffTime / 1000000L); if (deliveryCutOffList == null) { deliveryCutOffList = new ArrayList<>(); } deliveryCutOffList.add(deliveryCutOff); rawDelivery.setDeliveryEstimate(new DeliveryEstimate()); rawDelivery.getDeliveryEstimate().setDurationDesignator(serviceDurationDesignator); rawDelivery.getDeliveryEstimate().setDurationMinValue(row.getInt("service_duration_min_value") + i); rawDelivery.getDeliveryEstimate().setDurationMaxValue(row.getInt("service_duration_max_value") + i); rawDelivery.getDeliveryEstimate().setDurationMinValueWithLeadTime(row.getInt("service_duration_min_value") + i + sumLeadTimes); rawDelivery.getDeliveryEstimate().setDurationMaxValueWithLeadTime(row.getInt("service_duration_max_value") + i + sumLeadTimes); break; } } }//loop cutoffs if (deliveryCutOffList != null && deliveryCutOffList.size() > 0) rawDelivery.setDeliveryCutOff(deliveryCutOffList); if (rawDelivery.getDeliveryCutOff()!= null && rawDelivery.getDeliveryCutOff().size() > 0) { existingRawDeliveryList.add(rawDelivery); if (isDeliveryPaid ) { existingPaidRawDeliveryList = new ArrayList<>(); com.genpt.nsight.v4.model.RawDelivery paidRawDelivery = (com.genpt.nsight.v4.model.RawDelivery) JavaDeepClone.deepClone(rawDelivery); existingPaidRawDeliveryList.add(paidRawDelivery); } else { existingFreeRawDeliveryList = new ArrayList<>(); com.genpt.nsight.v4.model.RawDelivery freeRawDelivery = (com.genpt.nsight.v4.model.RawDelivery) JavaDeepClone.deepClone(rawDelivery); existingFreeRawDeliveryList.add(freeRawDelivery); } } //finished adding the first found rawDelivery }//end of else already have rawDelivery list for this site /// finally add it to the map, if the list is populated if (existingRawDeliveryList !=null && existingRawDeliveryList.size() > 0) quickestFreePaidDeliveryBySite.put(fromSiteID, existingRawDeliveryList); if (isDeliveryPaid) { if (existingPaidRawDeliveryList != null) { paidDeliveryBySite.put(fromSiteID, existingPaidRawDeliveryList); } } else { if (existingFreeRawDeliveryList != null) { freeDeliveryBySite.put(fromSiteID, existingFreeRawDeliveryList); } } }//end of check service duration designator } @Override public void setDeliveryByZip(AvailabilityServiceContextV4 availabilityServiceContextV3) { SplunkLogger splunkLogger = new SplunkLogger(availabilityServiceContextV3.getRequest().getHeaderRequest()); boolean localCrossedUTCMidnight = false; Map> quickestDeliveryBySite = new HashMap<>(); Map> freeDeliveryBySite = new HashMap<>(); Map> paidDeliveryBySite = new HashMap<>(); Map>> deliveryBySiteByDay = new HashMap<>(); /* if (Boolean.TRUE.equals(availabilityServiceContextV3.getRequest().getActionRequest().getAction().getNeedQuickestDelivery())){ //setOneDeliveryBySite(availabilityServiceContextV3); }else*/ { //create a set where we store all the 5 Digit deliveries Set fromSitesToZip = new HashSet<>(); //iterate over the futures from site to site rawDelivery paid table Map> deliveryBySite = availabilityServiceContextV3.getDeliveryZipEstimateFutures().stream().flatMap(resultSetListenableFuture -> { ResultSet resultSet = null; List rawDeliveryList = new ArrayList<>(); try { resultSet = resultSetListenableFuture.get(); while (!resultSet.isExhausted()) { Row row = resultSet.one(); String serviceDurationDesignator = row.getString("service_duration_designator"); com.genpt.nsight.v4.model.RawDelivery rawDelivery = createDelivery(serviceDurationDesignator, row, availabilityServiceContextV3, rawDeliveryList, fromSitesToZip); if (Boolean.TRUE.equals(availabilityServiceContextV3.isFreePaid())) { createFreePaidDelivery(serviceDurationDesignator, row, quickestDeliveryBySite, availabilityServiceContextV3, freeDeliveryBySite, paidDeliveryBySite); } } } catch (Exception ex) { ex.printStackTrace(); LOGGER.error(splunkLogger.toString() + " , Error in setDeliveryBySite, Message : {}, StackTrace: {} ", ex.getMessage(), ex.getStackTrace()); } return rawDeliveryList.stream(); }).collect(Collectors.groupingBy(delivery -> delivery.getSiteId())); availabilityServiceContextV3.setDeliveryByZip(deliveryBySite); // we might need to iterate over the futures from the new free rawDelivery table too only if its not for zip codes // there are no free deliverirs to a zip code if (Boolean.TRUE.equals(availabilityServiceContextV3.isFreePaid())) { availabilityServiceContextV3.setQuickestFreePaidDeliveryBySite(quickestDeliveryBySite); availabilityServiceContextV3.setFreeDeliveryBySite(freeDeliveryBySite); availabilityServiceContextV3.setPaidDeliveryBySite(paidDeliveryBySite); } //populate by site by day into a new map. This is for V4 where we store based on deliver day ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")); final ZonedDateTime beginningOfDay = now.truncatedTo(ChronoUnit.DAYS); // these are paid and free deliveries that we are iterating for (Map.Entry> entry : deliveryBySite.entrySet()) { //get from the raw data List deliveries = entry.getValue(); String siteID = entry.getKey(); //for this site get the List by Day Map> deliveryByDayMap= deliveryBySiteByDay.get(siteID); //for the day if we dont have one, create it if (deliveryByDayMap == null) deliveryByDayMap = new HashMap<>(); //from the raw data iterate over the deliveries by type for this site for (com.genpt.nsight.v4.model.RawDelivery rawDelivery : deliveries) { //iterate over each cutoff time from the raw data if (rawDelivery.getDeliveryCutOff() != null) { for (com.genpt.nsight.v4.model.DeliveryCutOff deliveryCutOff : rawDelivery.getDeliveryCutOff()) { boolean afterCutOff = false; String deliveryDayOfWeek = DeliveryCutOffSerializer.DAY_OF_WEEK[ deliveryCutOff.getDayOfTheWeek()]; //get the timezone to check if its after midnight which means its really late for that day float shipFromTZ = 0; boolean isNextDay = false; //String tz = nSightCache.getSiteIdToSiteMap().get(siteID).getTimeZone(); String tz = nSightCache.getSiteIdToSiteMap().get(availabilityServiceContextV3.getRequestingSite().getSiteIdentifier()).getTimeZone(); if (tz != null && tz.trim()!= "" && tz.trim().compareToIgnoreCase("NaN")!= 0 ) shipFromTZ = Float.parseFloat(nSightCache.getSiteIdToSiteMap().get(availabilityServiceContextV3.getRequestingSite().getSiteIdentifier()).getTimeZone()); if (availabilityServiceContextV3.getStoreOffSetTime()!=null && shipFromTZ !=0) { isNextDay = availabilityServiceContextV3.isCutOffNextDay(deliveryCutOff.getCutOffTime(), shipFromTZ); localCrossedUTCMidnight = availabilityServiceContextV3.isStorePastMidnightUTC(); } // if processing a current day cutoff, check if its past the cutoff time if (deliveryCutOff.getDayOfTheWeek() == availabilityServiceContextV3.getDayOfWeekLocal()) { //we are processing a current day cutoff if (availabilityServiceContextV3.getStoreOffSetTime() != null && shipFromTZ != 0) {// this needs to work for days, minutes, hours, etc. if (!availabilityServiceContextV3.requestTimeBeforeCutOffTime(deliveryCutOff.getCutOffTime(), shipFromTZ, rawDelivery.getDeliveryEstimate().getDurationMinValue()))//expects millis afterCutOff = true; } else { long nowCurrentDay = 1000000 * availabilityServiceContextV3.getTimeOfDay(); if (deliveryCutOff.getCutOffTime() < nowCurrentDay) afterCutOff = true; } } if (afterCutOff) continue;//not interested //Now create a new V4 RawDelivery Object com.genpt.nsight.v4.model.Delivery deliveryDay = new com.genpt.nsight.v4.model.Delivery();// deliveryDay.setDeliveryType(rawDelivery.getDeliveryType()); deliveryDay.setZone(rawDelivery.getZone()); //this is needed only internally deliveryDay.setDeliveryDestination(rawDelivery.getDeliveryDestination()); if (rawDelivery.getDeliveryCategory()!=null && rawDelivery.getDeliveryCategory().length() >0) deliveryDay.setDeliveryCategory(rawDelivery.getDeliveryCategory()); else deliveryDay.setDeliveryCategory("Ranged"); deliveryDay.setCutOffTime(deliveryCutOff.getCutOffTime()); deliveryDay.setDayOfWeek(deliveryCutOff.getDayOfTheWeek()); if (localCrossedUTCMidnight && !isNextDay) { ZonedDateTime beginningOfDayBack = beginningOfDay.minusDays(1); deliveryDay.setCutOffDateTime(availabilityServiceContextV3.getDateTime(0, deliveryCutOff.getCutOffTime(), beginningOfDayBack, isNextDay, "Days", deliveryDayOfWeek, localCrossedUTCMidnight)); }else deliveryDay.setCutOffDateTime(availabilityServiceContextV3.getDateTime(0, deliveryCutOff.getCutOffTime(), beginningOfDay, isNextDay, "Days", deliveryDayOfWeek, localCrossedUTCMidnight)); try { deliveryDay.setCutOffTimeString(nSightCache.getDeliveryCutOffTimeStore().get(deliveryCutOff.getCutOffTime())); } catch (ExecutionException e) { e.printStackTrace(); } deliveryDay.setDayofweekString(DeliveryCutOffSerializer.DAY_OF_WEEK[deliveryDay.getDayOfWeek()]); if (nSightProperties.getPaidMOTS().contains(rawDelivery.getDeliveryType())) deliveryDay.setFreeDelivery(false); else deliveryDay.setFreeDelivery(true); if (rawDelivery.getDeliveryEstimate()!=null) { com.genpt.nsight.v4.model.DeliveryEstimateFreePaid deliveryEstimateFreePaid = new com.genpt.nsight.v4.model.DeliveryEstimateFreePaid(); deliveryEstimateFreePaid.setDurationDesignator(rawDelivery.getDeliveryEstimate().getDurationDesignator()); deliveryEstimateFreePaid.setDurationMaxValue(rawDelivery.getDeliveryEstimate().getDurationMaxValue()); deliveryEstimateFreePaid.setDurationMinValue(rawDelivery.getDeliveryEstimate().getDurationMinValue()); //add the calculated fields if (localCrossedUTCMidnight && !isNextDay){ ZonedDateTime beginningOfDayBack = beginningOfDay.minusDays(1); deliveryEstimateFreePaid.setExpectationRangeMin(availabilityServiceContextV3.getDateTime(deliveryEstimateFreePaid.getDurationMinValue(), deliveryCutOff.getCutOffTime(), beginningOfDayBack, isNextDay, deliveryEstimateFreePaid.getDurationDesignator(), deliveryDayOfWeek, localCrossedUTCMidnight)); deliveryEstimateFreePaid.setExpectationRangeMax(availabilityServiceContextV3.getDateTime(deliveryEstimateFreePaid.getDurationMinValue(), deliveryCutOff.getCutOffTime(), beginningOfDayBack, isNextDay, deliveryEstimateFreePaid.getDurationDesignator(), deliveryDayOfWeek, localCrossedUTCMidnight)); }else { deliveryEstimateFreePaid.setExpectationRangeMin(availabilityServiceContextV3.getDateTime(deliveryEstimateFreePaid.getDurationMinValue(), deliveryCutOff.getCutOffTime(), beginningOfDay, isNextDay, deliveryEstimateFreePaid.getDurationDesignator(), deliveryDayOfWeek, localCrossedUTCMidnight)); deliveryEstimateFreePaid.setExpectationRangeMax(availabilityServiceContextV3.getDateTime(deliveryEstimateFreePaid.getDurationMinValue(), deliveryCutOff.getCutOffTime(), beginningOfDay, isNextDay, deliveryEstimateFreePaid.getDurationDesignator(), deliveryDayOfWeek, localCrossedUTCMidnight)); } availabilityServiceContextV3.translateTimesToLocal( deliveryDay, siteID, deliveryEstimateFreePaid, true); //availabilityServiceContextV3.populateExpectations(siteID, deliveryEstimateFreePaid, ZonedDateTime.parse(deliveryEstimateFreePaid.getExpectationRangeMin()), ZonedDateTime.parse(deliveryEstimateFreePaid.getExpectationRangeMax()), true); ////// if(!afterCutOff) deliveryDay.setDeliveryEstimate(deliveryEstimateFreePaid); } //check if a entry for the list exists for this by day List listByDay = deliveryByDayMap.get(deliveryCutOff.getDayOfTheWeek()); if(!afterCutOff) { if (listByDay == null) listByDay = new ArrayList<>(); listByDay.add(deliveryDay);// add to day list deliveryByDayMap.put(deliveryCutOff.getDayOfTheWeek(), listByDay); } }//iterate deliveries cutoffs by day } }//iterate by rawDelivery type //done with site. sort it for this site now List currentSitesDeliveries = new ArrayList<>(); List currentSitesDeliveriesLimited = new ArrayList<>(); //add all deliveries for ALL days of the week for (List value : deliveryByDayMap.values()) currentSitesDeliveries.addAll(value); //sort them by the arrival datetime Collections.sort(currentSitesDeliveries); //now put them in the map back after populating the arrival sequence number //iterate again over the options to update properties int i =0; boolean quickestPaid = false; boolean quickestFree = false; Map deliveryCountMap = new HashMap<>(); //iterate ove rthe sorteed list of deliveries for this site for ( com.genpt.nsight.v4.model.Delivery currentSiteDelivery : currentSitesDeliveries){ int total = 0; Integer integer = deliveryCountMap.get(currentSiteDelivery.getDeliveryType()); if (integer!=null) total=integer; if (total > 1) continue; deliveryCountMap.put(currentSiteDelivery.getDeliveryType(),++total); currentSiteDelivery.setDeliveryArrivalSeq(i+1); //set the quickest options if (i==0){ currentSiteDelivery.setQuickestOption(true); if (!currentSiteDelivery.isFreeDelivery()) quickestPaid = true; else quickestFree = true; }else{ if (quickestFree == false || quickestPaid == false) { if (quickestPaid = false && !currentSiteDelivery.isFreeDelivery()){ currentSiteDelivery.setQuickestOption(true); quickestPaid = true; } if (quickestFree == false && currentSiteDelivery.isFreeDelivery()) { currentSiteDelivery.setQuickestOption(true); quickestFree = true; } } } currentSitesDeliveriesLimited.add(currentSiteDelivery); i++; } //At this point we have the limited list of deliveries for this sorted in ascending order //availabilityServiceContextV3.getDeliveryBySiteSorted().put(siteID, currentSitesDeliveriesLimited); availabilityServiceContextV3.getDeliveryByZipSorted().put(siteID, currentSitesDeliveriesLimited); }//done with all sites // now we need to sort all the deliveries } } }