package com.genpt.nsight.v4; import com.datastax.driver.core.ResultSet; import com.datastax.driver.core.ResultSetFuture; import com.genpt.nsight.v1.model.*; import com.genpt.nsight.v1.model.POSService.POSServiceResponse; import com.genpt.nsight.v1.model.dto.SiteDTO; import com.genpt.nsight.v1.model.serializer.DeliveryCutOffSerializer; import com.genpt.nsight.v4.model.Expectation; import com.genpt.nsight.v4.model.StoreHours; import com.genpt.nsight.v4.model.inventory.availability.InventoryResponseMultiProduct; import com.genpt.nsight.v4.model.inventory.availability.InventoryResponseV1; import com.genpt.nsight.v4.model.majoraccounts.LocateProductRequest; import com.genpt.nsight.v4.model.majoraccounts.LocateProductResponse; import com.genpt.nsight.v4.service.delivery.DeliveryResponseV1; import com.google.common.util.concurrent.ListenableFuture; import lombok.Getter; import lombok.Setter; import org.springframework.stereotype.Service; import java.time.*; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; /** * Created by robin on 6/13/2021. */ @Getter @Setter @Service public class AvailabilityServiceContextV4 { private boolean verification; private boolean aggregate; private boolean freePaid; private long timeOfDay; private int dayOfWeekLocal; private com.genpt.nsight.v4.model.ProductAvailabilityRequest request; private com.genpt.nsight.v3.model.majoraccounts.LocateProductRequest requestMajorAccountsV3; private LocateProductRequest requestMajorAccounts; private Set partSet; private Map> virtualPart2ParentPartMap; private Map parentPartMap; private Map inputParts; private Map kitComponentMap; private SiteDTO requestingSite; private RelatedSite primaryDC; private Set relatedSites = new HashSet<>(); private Map> siteRelationMap = new HashMap<>(); private Map inventoryFutureUapDcInvCdMap = new HashMap<>(); private List> inventoryFutures; private List> availabilityInventoryFutures; private ListenableFuture> gcpInventoryFutures; private ListenableFuture gcpMultiProductInventoryFutures; private ListenableFuture> gcpFreeDeliveryFutures; private List gcpFreeDeliveryResponseList; private List> nonNapaInventoryFutures; private boolean isFreeDeliveryGCPRequestNeeded; //leadtimes private List> leadTimeFutures; private Map> leadTimeBySite; private Set fromSiteIds = new HashSet<>(); private List> deliveryEstimateFutures; private List> deliveryFreeEstimateFutures; //need a seperate one by zips private List> deliveryZipEstimateFutures; private Map> deliveryBySite; private Map> deliveryByZip; private Map> freeDeliveryBySite; private Map> paidDeliveryBySite; private Map> quickestFreePaidDeliveryBySite; private boolean skipHQLineAbbrev; private Map> inventory; private Map> gcpInventory; private Map> nonNapaInventory; private Map quickestDeliveryBySite; private Set siteWithPartsAvailable = new HashSet<>(); //Logging variables private String correlationID; private String applicationID; private String timeStamp; private boolean callNonTAMS; private String rpmURL; private String uapDCURL; private int rpmTimeout; private String rpmSecurity; private Set partRelatedSiteSet = new HashSet<>(); private Set zipCodesSet = new HashSet<>(); private Map shipToSitesMap = new HashMap<>(); private Map reverseShipToSitesMap = new HashMap<>(); private Map otherSitesPassword = new HashMap<>(); private Map otherSitesStoreNumber = new HashMap<>(); private OffsetTime storeOffSetTime; private String storeTimeZone; private String pricingStatusCode; private String pricingStatusMessage; private boolean combineDCQuantity= false; private boolean isMainCounter= false; private boolean needUAPDCQuantity= false; private String b2bSDK; private Map>> deliveryBySiteByDay; private Map> deliveryBySiteSorted = new HashMap<>(); private Map> deliveryByZipSorted = new HashMap<>(); private boolean needSiteToSiteAndZip= false; private int pickUpFromStoreOffset = 0; private int deliverFromStoreOffset = 0; private int deliverOnDemandOffset = 0; private int storeClosingOffset = 0; private String pickUpFromStoreOffsetRaw = null; private String deliverFromStoreOffsetRaw = null; private String deliverOnDemandOffsetRaw = null; private ZonedDateTime storeOpenToday; private ZonedDateTime storeCloseToday; private ZonedDateTime storeOpen; private ZonedDateTime storeClose; private ZonedDateTime storeOpenTomorrow; private ZonedDateTime storeCloseTomorrow; private ZonedDateTime nextStoreOpen; private ZonedDateTime nextStoreClose; private ZoneOffset storeZoneOffset; private String storeDayOfWeek; private ZonedDateTime storeCurrentTime; private String todayOffset; private String tomorrowTime; private ZonedDateTime today1CutoffTime; private ZonedDateTime tomorrow1CutoffTime; private boolean storeOpenIndicator= true; private boolean storeHolidayToday= false; private boolean afterStoreHours = false; private ArrayList requestingSiteStoreHoursList; public static final DateTimeFormatter LOCALFORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME; public static final DateTimeFormatter FORMATTER = DateTimeFormatter.ISO_INSTANT; private boolean useUTC= false; private String storeZoneID; private String defaultPaidExpectationTime; private Set sitesWithInventory = new HashSet<>(); private HashMap translatedPartMap = new HashMap<>(); private Optional sourceLocationsToGCP = Optional.empty(); private Optional sourceLocationsToNSight = Optional.empty(); public Tracking createInvalidTimezoneTracking(){ Tracking tracking = new Tracking(); tracking.setIsSuccess(Boolean.FALSE); tracking.setFault(Fault.builder().code("3005").message("Invalid Data - Timezone is null in NSight for requesting site").build()); //LOGGER.error(splunkLogger.toString() + " Invalid Data - Timezone is null in Nsight for requesting site: 3005"); return tracking; } public Tracking createInvalidTimezoneIDTracking(){ Tracking tracking = new Tracking(); tracking.setIsSuccess(Boolean.FALSE); tracking.setFault(Fault.builder().code("3005").message("Invalid Data - Timezone ID is null in NSight for requesting site").build()); return tracking; } public Tracking createInvalidStoreHoursTracking(){ Tracking tracking = new Tracking(); tracking.setIsSuccess(Boolean.FALSE); tracking.setFault(Fault.builder().code("3005").message("Invalid Data - Store Hours not present in NSight for requesting site").build()); return tracking; } public void setRequest(com.genpt.nsight.v4.model.ProductAvailabilityRequest productAvailabilityRequest) { if (productAvailabilityRequest.getHeaderRequest().getRequestor().getRequestorIdentifier().getType()!=null) productAvailabilityRequest.getHeaderRequest().getRequestor().getRequestorIdentifier().setType(productAvailabilityRequest.getHeaderRequest().getRequestor().getRequestorIdentifier().getType().trim()); if (productAvailabilityRequest.getHeaderRequest().getRequestor().getRequestorIdentifier().getValue() != null) productAvailabilityRequest.getHeaderRequest().getRequestor().getRequestorIdentifier().setValue(productAvailabilityRequest.getHeaderRequest().getRequestor().getRequestorIdentifier().getValue().trim()); productAvailabilityRequest.getDetailRequest().getParts().forEach(part -> { part.setPartNumber(part.getPartNumber().trim()); part.setLineAbbrev(part.getLineAbbrev().trim()); }); this.request = productAvailabilityRequest; this.applicationID = this.request.getHeaderRequest().getRequestor().getRequestorApplication(); this.correlationID = this.request.getHeaderRequest().getCorrelationId(); this.timeStamp= this.request.getHeaderRequest().getTimestamp(); } public com.genpt.nsight.v4.model.ProductAvailabilityResponse getProductAvailabilityResponseTemplate(AvailabilityServiceContextV4 availabilityServiceContextV3) { com.genpt.nsight.v4.model.ProductAvailabilityResponse productAvailabilityResponse = new com.genpt.nsight.v4.model.ProductAvailabilityResponse(); HeaderResponse headerResponse = new HeaderResponse(); headerResponse.setRequestor(availabilityServiceContextV3.getRequest().getHeaderRequest().getRequestor()); headerResponse.setResponder(availabilityServiceContextV3.getRequest().getHeaderRequest().getResponder()); headerResponse.setCountryCode(availabilityServiceContextV3.getRequest().getHeaderRequest().getCountryCode()); headerResponse.setLanguageCode(availabilityServiceContextV3.getRequest().getHeaderRequest().getLanguageCode()); headerResponse.setTimestamp(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())); productAvailabilityResponse.setCorrelationId(availabilityServiceContextV3.getRequest().getHeaderRequest().getCorrelationId()); productAvailabilityResponse.setHeaderResponse(headerResponse); return productAvailabilityResponse; } public com.genpt.nsight.v4.model.ProductAvailabilityResponseFreePaid getProductAvailabilityResponseFreePaidTemplate(AvailabilityServiceContextV4 availabilityServiceContextV3) { com.genpt.nsight.v4.model.ProductAvailabilityResponseFreePaid productAvailabilityResponseFreePaid = new com.genpt.nsight.v4.model.ProductAvailabilityResponseFreePaid(); HeaderResponse headerResponse = new HeaderResponse(); headerResponse.setRequestor(availabilityServiceContextV3.getRequest().getHeaderRequest().getRequestor()); headerResponse.setResponder(availabilityServiceContextV3.getRequest().getHeaderRequest().getResponder()); headerResponse.setCountryCode(availabilityServiceContextV3.getRequest().getHeaderRequest().getCountryCode()); headerResponse.setLanguageCode(availabilityServiceContextV3.getRequest().getHeaderRequest().getLanguageCode()); headerResponse.setTimestamp(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())); productAvailabilityResponseFreePaid.setCorrelationId(availabilityServiceContextV3.getRequest().getHeaderRequest().getCorrelationId()); productAvailabilityResponseFreePaid.setHeaderResponse(headerResponse); return productAvailabilityResponseFreePaid; } public com.genpt.nsight.v4.model.ProductAvailabilityAggResponseNOL getProductAvailabilityResponseNOL(AvailabilityServiceContextV4 availabilityServiceContextV3) { com.genpt.nsight.v4.model.ProductAvailabilityAggResponseNOL productAvailabilityResponseFreePaid = new com.genpt.nsight.v4.model.ProductAvailabilityAggResponseNOL(); HeaderResponse headerResponse = new HeaderResponse(); headerResponse.setRequestor(availabilityServiceContextV3.getRequest().getHeaderRequest().getRequestor()); headerResponse.setResponder(availabilityServiceContextV3.getRequest().getHeaderRequest().getResponder()); headerResponse.setCountryCode(availabilityServiceContextV3.getRequest().getHeaderRequest().getCountryCode()); headerResponse.setLanguageCode(availabilityServiceContextV3.getRequest().getHeaderRequest().getLanguageCode()); headerResponse.setTimestamp(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())); productAvailabilityResponseFreePaid.setCorrelationId(availabilityServiceContextV3.getRequest().getHeaderRequest().getCorrelationId()); productAvailabilityResponseFreePaid.setHeaderResponse(headerResponse); return productAvailabilityResponseFreePaid; } public com.genpt.nsight.v4.model.ProductAvailabilityAggResponseProlink getProductAvailabilityResponseProlink(AvailabilityServiceContextV4 availabilityServiceContextV3) { com.genpt.nsight.v4.model.ProductAvailabilityAggResponseProlink productAvailabilityResponseFreePaid = new com.genpt.nsight.v4.model.ProductAvailabilityAggResponseProlink(); HeaderResponse headerResponse = new HeaderResponse(); headerResponse.setRequestor(availabilityServiceContextV3.getRequest().getHeaderRequest().getRequestor()); headerResponse.setResponder(availabilityServiceContextV3.getRequest().getHeaderRequest().getResponder()); headerResponse.setCountryCode(availabilityServiceContextV3.getRequest().getHeaderRequest().getCountryCode()); headerResponse.setLanguageCode(availabilityServiceContextV3.getRequest().getHeaderRequest().getLanguageCode()); headerResponse.setTimestamp(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())); productAvailabilityResponseFreePaid.setCorrelationId(availabilityServiceContextV3.getRequest().getHeaderRequest().getCorrelationId()); productAvailabilityResponseFreePaid.setHeaderResponse(headerResponse); return productAvailabilityResponseFreePaid; } public com.genpt.nsight.v3.model.majoraccounts.LocateProductResponse getLocateProductResponseV3Template(AvailabilityServiceContextV4 availabilityServiceContextV4) { com.genpt.nsight.v3.model.majoraccounts.LocateProductResponse locateProductResponse = new com.genpt.nsight.v3.model.majoraccounts.LocateProductResponse(); HeaderResponse headerResponse = new HeaderResponse(); headerResponse.setRequestor(availabilityServiceContextV4.getRequestMajorAccounts().getHeaderRequest().getRequestor()); headerResponse.setResponder(availabilityServiceContextV4.getRequestMajorAccounts().getHeaderRequest().getResponder()); headerResponse.setCountryCode(availabilityServiceContextV4.getRequestMajorAccounts().getHeaderRequest().getCountryCode()); headerResponse.setLanguageCode(availabilityServiceContextV4.getRequestMajorAccounts().getHeaderRequest().getLanguageCode()); headerResponse.setTimestamp(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())); headerResponse.setCorrelationId(availabilityServiceContextV4.getRequestMajorAccounts().getHeaderRequest().getCorrelationId()); locateProductResponse.setHeaderResponse(headerResponse); return locateProductResponse; } public LocateProductResponse getLocateProductResponseTemplate(AvailabilityServiceContextV4 availabilityServiceContextV4) { LocateProductResponse locateProductResponse = new LocateProductResponse(); HeaderResponse headerResponse = new HeaderResponse(); headerResponse.setRequestor(availabilityServiceContextV4.getRequestMajorAccounts().getHeaderRequest().getRequestor()); headerResponse.setResponder(availabilityServiceContextV4.getRequestMajorAccounts().getHeaderRequest().getResponder()); headerResponse.setCountryCode(availabilityServiceContextV4.getRequestMajorAccounts().getHeaderRequest().getCountryCode()); headerResponse.setLanguageCode(availabilityServiceContextV4.getRequestMajorAccounts().getHeaderRequest().getLanguageCode()); headerResponse.setTimestamp(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())); headerResponse.setCorrelationId(availabilityServiceContextV4.getRequestMajorAccounts().getHeaderRequest().getCorrelationId()); locateProductResponse.setHeaderResponse(headerResponse); return locateProductResponse; } public boolean requestTimeBeforeCutOffTime (long deliveryCutOffTime, float cutOffOfset, int durationDays, SiteDTO shipFromSite){ //these are the cutofftimes for the ship from store OffsetTime cutOffTimeUTC = OffsetTime.of(LocalTime.ofSecondOfDay(deliveryCutOffTime / 1000L), ZoneOffset.UTC); OffsetTime cutOffTimeLocal = cutOffTimeUTC.withOffsetSameInstant(ZoneOffset.ofTotalSeconds((int) (cutOffOfset*60*60))); //we need to keep the cutoff local time same but switch the timezone based on ZoneID else the compare will be inaccurate //since we are using the from sites zoneid, we need to use its offset OffsetTime cutOffTimeLocalTZ = cutOffTimeLocal.withOffsetSameLocal(ZoneId.of(shipFromSite.getTimeZoneID()).getRules().getOffset(Instant.now())); //OffsetTime cutOffTimeLocal = cutOffTimeUTC.withOffsetSameInstant(ZoneOffset.ofHours(cutOffOfset)); // if (durationDays==0) { //Need to handle cutoff times that are passed UTC due to UTC translation /* if (isCutOffNextDay(deliveryCutOffTime, cutOffOfset)) { return false; } else*/ ZonedDateTime nowShipFrom = ZonedDateTime.now(ZoneId.of(shipFromSite.getTimeZoneID())); OffsetDateTime localTimeShipFrom = nowShipFrom.toOffsetDateTime(); OffsetTime shipFromOffsetTime = localTimeShipFrom.toOffsetTime(); return shipFromOffsetTime.isBefore(cutOffTimeLocalTZ); /* }else return storeOffSetTime.isBefore(cutOffTimeLocal);*/ } public boolean requestDateTimeBeforeCutOffTime (String deliveryCutOffDateTime, float cutOffOfset, int durationDays, SiteDTO shipFromSite){ String dateFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'"; DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat); LocalDateTime dateTime = LocalDateTime.parse(deliveryCutOffDateTime, formatter); OffsetDateTime cutOffDateTimeUTC = OffsetDateTime.of(dateTime, ZoneOffset.UTC); OffsetDateTime cutOffDateTimeLocal = cutOffDateTimeUTC.withOffsetSameInstant(ZoneOffset.ofTotalSeconds((int) (cutOffOfset*60*60))); OffsetDateTime deliveryCutOffOffSetDateTime = cutOffDateTimeLocal .withOffsetSameLocal(ZoneId.of(shipFromSite.getTimeZoneID()).getRules().getOffset(Instant.now())); ZonedDateTime nowShipFrom = ZonedDateTime.now(ZoneId.of(shipFromSite.getTimeZoneID())); OffsetDateTime localTimeShipFrom = nowShipFrom.toOffsetDateTime(); return localTimeShipFrom.isBefore(deliveryCutOffOffSetDateTime); } public boolean cutOffTimeAfterMax (long deliveryCutOffTime, long MaxCutOffTime, float cutOffOfset, float maxCutOffOfset){ //check if we have the timezones offset else just use the times if (cutOffOfset != 0 && maxCutOffOfset!=0) { OffsetTime cutOffTimeUTC = OffsetTime.of(LocalTime.ofSecondOfDay(deliveryCutOffTime / 1000L), ZoneOffset.UTC); //OffsetTime cutOffTimeLocal = cutOffTimeUTC.withOffsetSameInstant(ZoneOffset.ofHours(cutOffOfset)); OffsetTime cutOffTimeLocal = cutOffTimeUTC.withOffsetSameInstant(ZoneOffset.ofTotalSeconds((int) (cutOffOfset * 60 * 60))); OffsetTime maxcutOffTimeUTC = OffsetTime.of(LocalTime.ofSecondOfDay(MaxCutOffTime / 1000L), ZoneOffset.UTC); //OffsetTime maxcutOffTimeLocal = maxcutOffTimeUTC.withOffsetSameInstant(ZoneOffset.ofHours(maxCutOffOfset)); OffsetTime maxcutOffTimeLocal = maxcutOffTimeUTC.withOffsetSameInstant(ZoneOffset.ofTotalSeconds((int) (maxCutOffOfset*60*60))); return cutOffTimeLocal.isAfter(maxcutOffTimeLocal); }else{ return deliveryCutOffTime > MaxCutOffTime ? true : false; } } public boolean isCutOffNextDay(long deliveryCutoffTime, float cutOffOffset){ boolean nextDay = false; long millisToLocalDay = (long) (deliveryCutoffTime + cutOffOffset*60*60*1000); if (millisToLocalDay < 0) nextDay= true; return nextDay; } public boolean isStorePastMidnightUTC(){ boolean crossedUTCNextDay = false; //if the store is also crossed over its UTC time to next day then this should be false // we need to check if the stores current day in UTC is the same as the current UTC time //if they are the same nexDtDay should be false ZonedDateTime storeUTC = getStoreCurrentTime().toInstant().atZone(ZoneId.of("UTC")); if (getStoreZoneID() != null) { ZonedDateTime storeLocal = getStoreCurrentTime().toInstant().atZone(ZoneId.of(getStoreZoneID())); if (storeUTC.getDayOfMonth() != storeLocal.getDayOfMonth()) crossedUTCNextDay = true; } return crossedUTCNextDay; } public boolean isStorePastMidnightUTC(String storeZoneID){ boolean crossedUTCNextDay = false; //if the store is also crossed over its UTC time to next day then this should be false // we need to check if the stores current day in UTC is the same as the current UTC time //if they are the same nexDtDay should be false ZonedDateTime storeUTC = getStoreCurrentTime().toInstant().atZone(ZoneId.of("UTC")); ZonedDateTime storeLocal = getStoreCurrentTime().toInstant().atZone(ZoneId.of(storeZoneID)); if (storeUTC.getDayOfMonth()!=storeLocal.getDayOfMonth()) crossedUTCNextDay=true; return crossedUTCNextDay; } public boolean isEarliestNextDay(long deliveryCutoffTime, float cutOffOffset){ boolean nextDay = false; long millisToLocalDay = (long) (deliveryCutoffTime + cutOffOffset*60*60*1000); if (millisToLocalDay < 0) nextDay= true; return nextDay; } public long getMillisFromMidnight(ZonedDateTime now) { ZonedDateTime midnight = now.truncatedTo(ChronoUnit.DAYS); Duration duration = Duration.between(midnight, now); TimeZone tz = TimeZone.getDefault(); boolean isOn = ZoneId.of(tz.getID()) // Represent a specific time zone, the history of past, present, and future changes to the offset-from-UTC used by the people of a certain region. .getRules() // Obtain the list of those changes in offset. .isDaylightSavings( // See if the people of this region are observing Daylight Saving Time at a specific moment. Instant.now() // Specify the moment. Here we capture the current moment at runtime. ) ; // Returns a boolean. if (isOn) return duration.getSeconds() * 1000L +tz.getDSTSavings(); else return duration.getSeconds() * 1000L; } public long getMilliSecondsFromMidnight(ZonedDateTime now) { ZonedDateTime midnight = now.truncatedTo(ChronoUnit.DAYS); Duration duration = Duration.between(midnight, now); return duration.getSeconds() * 1000L; } public void setDayOfWeekLocalStore(SiteDTO callingStoreDTO){ //String storeTZ = callingStoreDTO.getTimeZone(); //ZoneOffset zoneOffSet = ZoneOffset.ofTotalSeconds((int) (Float.parseFloat(storeTZ) * 60 * 60)); ZonedDateTime now = ZonedDateTime.now(ZoneId.of(callingStoreDTO.getTimeZoneID())); //OffsetDateTime localTime = OffsetDateTime.now(zoneOffSet); // this is probably the fix for the store hour offset being not correct after daylight savings and the store time being an hour behind OffsetDateTime localTime = now.toOffsetDateTime(); setDayOfWeekLocal(localTime.getDayOfWeek().getValue() - 1); setTimeOfDay(getMillisFromMidnight(now)); setStoreOffSetTime(localTime.toOffsetTime()); } public int getDaysAfterToday(String deliveryDay){ int daysAfterToday =0; if (Arrays.asList(DeliveryCutOffSerializer.DAY_OF_WEEK).indexOf(deliveryDay) >= getDayOfWeekLocal()) daysAfterToday = Arrays.asList(DeliveryCutOffSerializer.DAY_OF_WEEK).indexOf(deliveryDay) - getDayOfWeekLocal(); else daysAfterToday = Arrays.asList(DeliveryCutOffSerializer.DAY_OF_WEEK).indexOf(deliveryDay) + 7 - getDayOfWeekLocal(); return daysAfterToday; } /* * This function is used to operate on the raw data which is always in or based off UTC * */ public String getDateTime(int duration, long timeInMills, ZonedDateTime now, boolean nextDay, String durationDesignator, String deliveryDay, boolean localCrossedUTCMidnight) { long minutes = timeInMills / (60 * 1000L); String dateTime = null; int daysAfterToday = getDaysAfterToday(deliveryDay); try { if (nextDay && !localCrossedUTCMidnight) { //dateTime = DateTimeFormatter.ISO_INSTANT.format(now.plusDays(duration + 1).plusMinutes(minutes)); if (durationDesignator.compareToIgnoreCase("Days")==0) dateTime = DateTimeFormatter.ISO_INSTANT.format(now.plusDays(duration+daysAfterToday+1).plusMinutes(minutes)); else if (durationDesignator.compareToIgnoreCase("Minutes")==0){ minutes = minutes + duration; dateTime = DateTimeFormatter.ISO_INSTANT.format(now.plusDays(daysAfterToday+1).plusMinutes(minutes)); } else if (durationDesignator.compareToIgnoreCase("Hours")==0){ minutes = minutes + duration*60; dateTime = DateTimeFormatter.ISO_INSTANT.format(now.plusDays(daysAfterToday+1).plusMinutes(minutes)); } } else { if (durationDesignator.compareToIgnoreCase("Days")==0) dateTime = DateTimeFormatter.ISO_INSTANT.format(now.plusDays(duration+daysAfterToday).plusMinutes(minutes)); else if (durationDesignator.compareToIgnoreCase("Minutes")==0){ minutes = minutes + duration; dateTime = DateTimeFormatter.ISO_INSTANT.format(now.plusDays(daysAfterToday).plusMinutes(minutes)); } else if (durationDesignator.compareToIgnoreCase("Hours")==0){ minutes = minutes + duration*60; dateTime = DateTimeFormatter.ISO_INSTANT.format(now.plusDays(daysAfterToday).plusMinutes(minutes)); } } } catch (Exception e) { e.printStackTrace(); } return dateTime; } public int getLeadTimesForSite(String dayOfWeek, String fromSiteID, String deliveryServiceType ){ int sumLeadTimes = 0; if (getLeadTimeBySite()!= null && getLeadTimeBySite().containsKey(fromSiteID)){ //need to get it for the corresponding day of week List copy = getLeadTimeBySite().get(fromSiteID).stream() .filter(s -> s.getDeliveryServiceType().compareToIgnoreCase(deliveryServiceType) == 0 && s.getDayOfTheWeek().compareToIgnoreCase(dayOfWeek) == 0) .collect(Collectors.toList()); //copy = copy.stream().filter(s -> s.getDayOfTheWeek().compareToIgnoreCase(dayOfWeek) == 0 ).collect(Collectors.toList()); if (copy.size() > 0) sumLeadTimes = copy.stream().mapToInt(o -> o.getLeadTime()).sum(); } return sumLeadTimes; } public String calculateTimeBasedOnOffset(ZonedDateTime baseTimeUsed, int anyOffset){ String calculatedDate = ""; ZonedDateTime baseTimeUsedNormalized = baseTimeUsed.withZoneSameLocal(getStoreZoneOffset()); calculatedDate= isUseUTC() ? baseTimeUsedNormalized.plusMinutes(anyOffset).truncatedTo(ChronoUnit.SECONDS).format(FORMATTER) : baseTimeUsedNormalized.plusMinutes(anyOffset).truncatedTo(ChronoUnit.SECONDS).format(LOCALFORMATTER); return calculatedDate; } public String calculateUTCorLocalTimeBasedOnOffset(ZonedDateTime baseTimeUsed, int anyOffset, boolean isUTC){ String calculatedDate = ""; ZonedDateTime baseTimeUsedNormalized = baseTimeUsed.withZoneSameLocal(getStoreZoneOffset()); calculatedDate= isUTC ? baseTimeUsedNormalized.plusMinutes(anyOffset).truncatedTo(ChronoUnit.SECONDS).format(FORMATTER) : baseTimeUsedNormalized.plusMinutes(anyOffset).truncatedTo(ChronoUnit.SECONDS).format(LOCALFORMATTER); return calculatedDate; } public String calculateLocalTimeBasedOnTime(ZonedDateTime baseTimeUsed, int anyOffset){ String calculatedDate = ""; ZonedDateTime baseTimeUsedNormalized = baseTimeUsed.withZoneSameLocal(getStoreZoneOffset()); if (isStoreOpenIndicator()){ //we are within the store hours but check based on calculated values if (getStoreCurrentTime().withZoneSameLocal(getStoreZoneOffset()).plusMinutes(anyOffset).isAfter(getStoreClose().withZoneSameLocal(getStoreZoneOffset()))) { //we know the store is open but after the offset its beyond closed, so use tomorrows start if (getStoreOpenTomorrow() !=null) calculatedDate = isUseUTC()? getStoreOpenTomorrow().withZoneSameLocal(getStoreZoneOffset()).plusMinutes(anyOffset).truncatedTo(ChronoUnit.SECONDS).format(FORMATTER):getStoreOpenTomorrow().withZoneSameLocal(getStoreZoneOffset()).plusMinutes(anyOffset).truncatedTo(ChronoUnit.SECONDS).format(LOCALFORMATTER); else if (getNextStoreOpen()!=null) calculatedDate = isUseUTC()? getNextStoreOpen().withZoneSameLocal(getStoreZoneOffset()).plusMinutes(anyOffset).truncatedTo(ChronoUnit.SECONDS).format(FORMATTER):getNextStoreOpen().withZoneSameLocal(getStoreZoneOffset()).plusMinutes(anyOffset).truncatedTo(ChronoUnit.SECONDS).format(LOCALFORMATTER); }else calculatedDate= isUseUTC()? getStoreCurrentTime().withZoneSameLocal(getStoreZoneOffset()).plusMinutes(anyOffset).truncatedTo(ChronoUnit.SECONDS).format(FORMATTER) : getStoreCurrentTime().withZoneSameLocal(getStoreZoneOffset()).plusMinutes(anyOffset).truncatedTo(ChronoUnit.SECONDS).format(LOCALFORMATTER); }else if (baseTimeUsedNormalized.isBefore(getStoreOpen().withZoneSameLocal(getStoreZoneOffset())) || baseTimeUsedNormalized.isEqual(getStoreOpen().withZoneSameLocal(getStoreZoneOffset()))){ // should be store start time + offset. the store open would be tomorrows since its already closed calculatedDate= isUseUTC()? getStoreOpen().withZoneSameLocal(getStoreZoneOffset()).plusMinutes(anyOffset).truncatedTo(ChronoUnit.SECONDS).format(FORMATTER) : getStoreOpen().withZoneSameLocal(getStoreZoneOffset()).plusMinutes(anyOffset).truncatedTo(ChronoUnit.SECONDS).format(LOCALFORMATTER); }else if (baseTimeUsedNormalized.isAfter(getStoreClose().withZoneSameLocal(getStoreZoneOffset()))){ // need to check if its open the next day and then calculate the datetime //shouldnt reach here } return calculatedDate; } private boolean expectationAfterClose(String expectationDateTime){ boolean isAfterClose = false; ZonedDateTime expectedMax = parseDateTime(expectationDateTime, false); //if (expectedMax.isAfter(getStoreClose())) if (expectedMax.withZoneSameLocal(getStoreZoneOffset()).isAfter(getStoreClose().withZoneSameLocal(getStoreZoneOffset()))) isAfterClose=true; return isAfterClose; } private boolean expectationAfterCloseToday(String expectationDateTime){ boolean isAfterClose = false; ZonedDateTime expectedMax = parseDateTime(expectationDateTime, false); if (getStoreCloseToday()!=null) { if (expectedMax.withZoneSameLocal(getStoreZoneOffset()).isAfter(getStoreCloseToday().withZoneSameLocal(getStoreZoneOffset()))) isAfterClose = true; }else isAfterClose = true; return isAfterClose; } // this function operates on Delivery object that has the cutoff times in UTC from the table public void translateTimesToLocal(com.genpt.nsight.v4.model.Delivery deliveryDay, String siteID, com.genpt.nsight.v4.model.DeliveryEstimateFreePaid deliveryEstimateFreePaid, boolean deliverToZip){ //for V4 convert cutoff time and expectations to local time ZonedDateTime expectedMax; ZonedDateTime expectedMin; Instant timestampCO = Instant.parse(deliveryDay.getCutOffDateTime());// this is stored as UTC in the table deliveryDay.setZoneId(getStoreZoneID()); ZonedDateTime cutoffTime = timestampCO.atZone(ZoneId.of(getStoreZoneOffset().getId())); Instant timestamp = Instant.parse(deliveryEstimateFreePaid.getExpectationRangeMax());//always UTC Instant timestampMin = Instant.parse(deliveryEstimateFreePaid.getExpectationRangeMin());//always UTC expectedMax = timestamp.atZone(ZoneId.of(getStoreZoneOffset().getId())); expectedMin = timestampMin.atZone(ZoneId.of(getStoreZoneOffset().getId())); boolean isInDays = deliveryEstimateFreePaid.getDurationDesignator().compareToIgnoreCase("Days")==0? true : false; //for V4 we need to update the hours and minutes if its in days if (isInDays){ //change the hours and minutes if (!deliveryDay.isFreeDelivery()) {//paid. get the default value from config if (getDefaultPaidExpectationTime()!=null && getDefaultPaidExpectationTime().length() > 0){ String[] arrOfStr = getDefaultPaidExpectationTime().split(":"); if (arrOfStr!=null && arrOfStr.length > 1){ expectedMax = expectedMax.withHour(Integer.parseInt(arrOfStr[0])); expectedMax = expectedMax.withMinute(Integer.parseInt(arrOfStr[1])); expectedMin = expectedMin.withHour(Integer.parseInt(arrOfStr[0])); expectedMin = expectedMin.withMinute(Integer.parseInt(arrOfStr[1])); } }else { expectedMax = expectedMax.withHour(20); expectedMax = expectedMax.withMinute(00); expectedMin = expectedMin.withHour(20); expectedMin = expectedMin.withMinute(00); } }else{//should we get that days closing hours ? This is a free delivery StoreHours storeHours = getStoreHoursForSiteForDayOfWeek( siteID, expectedMax.getDayOfWeek().getValue()); if (storeHours != null) {// these are in local times boolean isTodayDelivery = expectedMax.toLocalDate().equals(LocalDate.now(expectedMax.getZone())); if (isTodayDelivery && isAfterStoreHours()){ expectedMax = getNextStoreOpen(); expectedMin = getNextStoreOpen(); } else { ZonedDateTime localDateTimeClose = ZonedDateTime.now(ZoneId.of(getStoreZoneOffset().getId())).withHour(storeHours.getClose().getHour()).withMinute(storeHours.getClose().getMinute()).minusMinutes(getStoreClosingOffset()).withSecond(0); expectedMax = expectedMax.withHour(localDateTimeClose.getHour()); expectedMax = expectedMax.withMinute(localDateTimeClose.getMinute()); expectedMin = expectedMin.withHour(localDateTimeClose.getHour()); expectedMin = expectedMin.withMinute(localDateTimeClose.getMinute()); } } } } DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss"); if (!this.isUseUTC())//change it to lcaol only if required else leave it as UTC deliveryDay.setCutOffTimeString(cutoffTime.format(formatter)); deliveryDay.setCutOffDateTime(calculateUTCorLocalTimeBasedOnOffset(cutoffTime, 0, this.isUseUTC())); deliveryEstimateFreePaid.setExpectationRangeMax(calculateUTCorLocalTimeBasedOnOffset(expectedMax, 0, this.isUseUTC())); deliveryEstimateFreePaid.setExpectationRangeMin(calculateUTCorLocalTimeBasedOnOffset(expectedMin, 0, this.isUseUTC())); //for V4 we need to consider store hours and expectations for any current day expectations // for V4 enhancements we have the new expectations structure. need to convert to local time of calling store if (isInDays) populateExpectations(deliveryDay,siteID, deliveryEstimateFreePaid, expectedMin, expectedMax, this.isUseUTC(), false, deliverToZip);//no offsets else populateExpectations(deliveryDay, siteID, deliveryEstimateFreePaid, expectedMin, expectedMax, this.isUseUTC(), true, deliverToZip);//use offsets } public void populateExpectations(com.genpt.nsight.v4.model.Delivery deliveryDay, String siteUUID, com.genpt.nsight.v4.model.DeliveryEstimateFreePaid deliveryEstimateFreePaid, ZonedDateTime expMin, ZonedDateTime expMax, boolean isUTC, boolean useOffsets, boolean deliverToZip){ ArrayList expectationArray = new ArrayList<>(); // for deliveries that are in days we need to use 20:00 for paid deliveries and store close for free deliveries //we need to create only expectations that are passed in boolean isTodayDelivery = expMin.toLocalDate().equals(LocalDate.now(expMin.getZone())); if (deliverToZip){//not going to the store. so dont need all the offsets here. Expectation expectation = new Expectation(); int offsetPickup = 0; expectation.setExpectationRangeMax(calculateUTCorLocalTimeBasedOnOffset(expMax, offsetPickup, isUTC)); expectation.setExpectationRangeMin(calculateUTCorLocalTimeBasedOnOffset(expMin, offsetPickup, isUTC)); expectationArray.add(expectation); } else {//delivering to the store //one thing to note for deliveries that are in minutes or hours is that if the calculated expectations are past the //stores working hours then use the next store open + offset for the hour and minutes and that date. //this applies only to where the expectation was for current day if (isStoreHolidayToday() && isTodayDelivery && !useOffsets){//store closed, todays, Days // need to change the date to the next working day open if its free. the store open would already be set to that date expMax = expMax.withYear(getStoreOpen().getYear()).withMonth(getStoreOpen().getMonthValue()).withDayOfMonth(getStoreOpen().getDayOfMonth()); expMin = expMin.withYear(getStoreOpen().getYear()).withMonth(getStoreOpen().getMonthValue()).withDayOfMonth(getStoreOpen().getDayOfMonth()); } //if its in minutes or hours and the store is closed then the expectation has to move to the next working days store open for a today delivery // this is only applicable for Non On Demand categories if (isStoreHolidayToday() && isTodayDelivery && useOffsets) {//store closed, todays, Minutes. There are only Free as of now // so essentially set the exp to next working days store open only if the calc expectation is not within store hours for Non On Demand //if (deliveryDay.getDeliveryCategory().compareToIgnoreCase("On Demand")!=0 && expectationAfterClose(calculateUTCorLocalTimeBasedOnOffset(expMin,0,isUTC))) { if (expectationAfterClose(calculateUTCorLocalTimeBasedOnOffset(expMin,0,isUTC))) { expMax = getStoreOpen(); expMin = getStoreOpen(); } } //calculate the pickup from store expectations if required if (getPickUpFromStoreOffsetRaw() != null) { Expectation expectation = new Expectation(); int offsetPickup = 0; if (useOffsets) offsetPickup = getPickUpFromStoreOffset(); expectation.setExpectationRangeMax(calculateUTCorLocalTimeBasedOnOffset(expMax, offsetPickup, isUTC)); expectation.setExpectationRangeMin(calculateUTCorLocalTimeBasedOnOffset(expMin, offsetPickup, isUTC)); //if the store is open, todays delivery, in minutes or hours and the calculated exp is after store close // this needs to be done only for Non On Demand //probably need the same after store hours logic for even On demand deliveries //if (deliveryDay.getDeliveryCategory().compareToIgnoreCase("On Demand")!=0) { if ( isTodayDelivery && useOffsets) { if (expectationAfterCloseToday(expectation.getExpectationRangeMax())) {// then need to update to next store open expectation.setExpectationRangeMax(calculateUTCorLocalTimeBasedOnOffset(nextStoreOpen, offsetPickup, isUTC)); } if (expectationAfterCloseToday(expectation.getExpectationRangeMin())) {// then need to update to next store open expectation.setExpectationRangeMin(calculateUTCorLocalTimeBasedOnOffset(nextStoreOpen, offsetPickup, isUTC)); } } } deliveryEstimateFreePaid.setExpectationRangeMaxPickup(expectation.getExpectationRangeMax()); deliveryEstimateFreePaid.setExpectationRangeMinPickup(expectation.getExpectationRangeMin()); expectation.setOffsetName("Pickup from Store"); expectation.setOffsetValue(String.valueOf(getPickUpFromStoreOffset())); expectationArray.add(expectation); } //calculate the deliver from store expectations if required if (getDeliverFromStoreOffsetRaw() != null) { Expectation expectationDeliver = new Expectation(); int offsetDeliver = 0; if (useOffsets) offsetDeliver = getDeliverFromStoreOffset(); expectationDeliver.setExpectationRangeMax(calculateUTCorLocalTimeBasedOnOffset(expMax, offsetDeliver, isUTC)); expectationDeliver.setExpectationRangeMin(calculateUTCorLocalTimeBasedOnOffset(expMin, offsetDeliver, isUTC)); //if the store is open, todays delivery, in minutes or hours and the calculated exp is after store close // this needs to be done only for Non On Demand //if (deliveryDay.getDeliveryCategory().compareToIgnoreCase("On Demand")!=0) { if (isTodayDelivery && useOffsets) { if (expectationAfterCloseToday(expectationDeliver.getExpectationRangeMax())) {// then need to update to next store open expectationDeliver.setExpectationRangeMax(calculateUTCorLocalTimeBasedOnOffset(nextStoreOpen, offsetDeliver, isUTC)); } if (expectationAfterCloseToday(expectationDeliver.getExpectationRangeMin())) {// then need to update to next store open expectationDeliver.setExpectationRangeMin(calculateUTCorLocalTimeBasedOnOffset(nextStoreOpen, offsetDeliver, isUTC)); } } } deliveryEstimateFreePaid.setExpectationRangeMaxDeliver(expectationDeliver.getExpectationRangeMax()); deliveryEstimateFreePaid.setExpectationRangeMinDeliver(expectationDeliver.getExpectationRangeMin()); expectationDeliver.setOffsetName("Deliver from Store"); expectationDeliver.setOffsetValue(String.valueOf(getDeliverFromStoreOffset())); expectationArray.add(expectationDeliver); } //calculate the deliver on demand expectations if required if (getDeliverOnDemandOffsetRaw() != null) { Expectation expectationDeliveronDemand = new Expectation(); int offsetDeliveronDemand = 0; if (useOffsets) offsetDeliveronDemand = getDeliverOnDemandOffset(); expectationDeliveronDemand.setExpectationRangeMax(calculateUTCorLocalTimeBasedOnOffset(expMax, offsetDeliveronDemand, isUTC)); expectationDeliveronDemand.setExpectationRangeMin(calculateUTCorLocalTimeBasedOnOffset(expMin, offsetDeliveronDemand, isUTC)); deliveryEstimateFreePaid.setExpectationRangeMaxOnDemand(expectationDeliveronDemand.getExpectationRangeMax()); deliveryEstimateFreePaid.setExpectationRangeMinOnDemand(expectationDeliveronDemand.getExpectationRangeMin()); //if the store is open, todays delivery, in minutes or hours and the calculated exp is after store close // this needs to be done only for Non On Demand //if (deliveryDay.getDeliveryCategory().compareToIgnoreCase("On Demand")!=0) { if ( isTodayDelivery && useOffsets) { if (expectationAfterCloseToday(expectationDeliveronDemand.getExpectationRangeMax())) {// then need to update to next store open expectationDeliveronDemand.setExpectationRangeMax(calculateUTCorLocalTimeBasedOnOffset(nextStoreOpen, offsetDeliveronDemand, isUTC)); } if (expectationAfterCloseToday(expectationDeliveronDemand.getExpectationRangeMin())) {// then need to update to next store open expectationDeliveronDemand.setExpectationRangeMin(calculateUTCorLocalTimeBasedOnOffset(nextStoreOpen, offsetDeliveronDemand, isUTC)); } } } expectationDeliveronDemand.setOffsetName("Deliver on Demand"); expectationDeliveronDemand.setOffsetValue(String.valueOf(getDeliverOnDemandOffset())); expectationArray.add(expectationDeliveronDemand); } } if (expectationArray.size()==0){// this would be if not offsets are passed in //need a default set of values Expectation expectation = new Expectation(); expectation.setExpectationRangeMax(calculateUTCorLocalTimeBasedOnOffset(expMax, 0, isUTC)); expectation.setExpectationRangeMin(calculateUTCorLocalTimeBasedOnOffset(expMin, 0, isUTC)); expectationArray.add(expectation); } //we need to set which is the quickest expectation at this point assignQuickestExpectation(deliveryEstimateFreePaid,expectationArray, false ); if (expectationArray !=null && expectationArray.size() >0) deliveryEstimateFreePaid.setExpectations(expectationArray); } public void assignQuickestExpectation(com.genpt.nsight.v4.model.DeliveryEstimateFreePaid deliveryEstimateFreePaid, List expectationArray, boolean updateDelivery ){ //we need to set which is the quickest expectation at this point if (expectationArray!=null && expectationArray.size() > 0){ for (Expectation expectation : expectationArray){//loop through them ZonedDateTime curExpectedMin = null; curExpectedMin = parseDateTime(expectation.getExpectationRangeMin(), false); if (deliveryEstimateFreePaid.getQuickestExpectationOfAllMin()==null) deliveryEstimateFreePaid.setQuickestExpectationOfAllMin(curExpectedMin); else{ if (curExpectedMin.isBefore(deliveryEstimateFreePaid.getQuickestExpectationOfAllMin())) deliveryEstimateFreePaid.setQuickestExpectationOfAllMin(curExpectedMin); } //update the delivery attributes too if (updateDelivery){ if (expectation.getOffsetName() !=null && expectation.getOffsetName().compareToIgnoreCase("Deliver from Store")==0){ deliveryEstimateFreePaid.setExpectationRangeMinDeliver(expectation.getExpectationRangeMin()); deliveryEstimateFreePaid.setExpectationRangeMaxDeliver(expectation.getExpectationRangeMax()); } if (expectation.getOffsetName() !=null && expectation.getOffsetName().compareToIgnoreCase("Pickup from Store")==0){ deliveryEstimateFreePaid.setExpectationRangeMinPickup(expectation.getExpectationRangeMin()); deliveryEstimateFreePaid.setExpectationRangeMaxPickup(expectation.getExpectationRangeMax()); } if (expectation.getOffsetName() !=null && expectation.getOffsetName().compareToIgnoreCase("Deliver on Demand")==0){ deliveryEstimateFreePaid.setExpectationRangeMinOnDemand(expectation.getExpectationRangeMin()); deliveryEstimateFreePaid.setExpectationRangeMaxOnDemand(expectation.getExpectationRangeMax()); } } } }else{ //we can default to the expected minimum since no offsets were passed in ZonedDateTime curExpectedMin = parseDateTime(deliveryEstimateFreePaid.getExpectationRangeMin(),false);; ZonedDateTime curExpectedMax = parseDateTime(deliveryEstimateFreePaid.getExpectationRangeMax(), false);; deliveryEstimateFreePaid.setQuickestExpectationOfAllMin(curExpectedMin); deliveryEstimateFreePaid.setQuickestExpectationOfAllMax(curExpectedMax); } } public StoreHours getStoreHoursForSiteForDayOfWeek(String siteUUID, int storeDayOfWeek){//DOW is 1 based but the storeslist is 0 based StoreHours storeHours = getRequestingSiteStoreHoursList().get(storeDayOfWeek - 1);//start looking from today return storeHours; } public ZonedDateTime parseDateTime(String dateTimeString, boolean useZoneID){ ZonedDateTime expectedMax = null; if (this.isUseUTC()){ Instant timestampMax = Instant.parse(dateTimeString); if(useZoneID) expectedMax = timestampMax.atZone(ZoneId.of(getStoreZoneID())); else expectedMax = timestampMax.atZone(ZoneId.of(getStoreZoneOffset().getId())); }else { LocalDateTime timestampMax = LocalDateTime.parse(dateTimeString, LOCALFORMATTER); if (useZoneID) expectedMax = timestampMax.atZone(ZoneId.of(getStoreZoneID())); else expectedMax = timestampMax.atZone(ZoneId.of(getStoreZoneOffset().getId())); } return expectedMax; } public void setStoreOpenCloseHours( ArrayList storeHoursList, ZonedDateTime localNow, String zoneID) { setRequestingSiteStoreHoursList(storeHoursList); setStoreZoneID(zoneID); // now we can work on this list int index = localNow.getDayOfWeek().getValue()-1; int foundIndex = 0; for (int i = 0; i < 7; i++) { StoreHours storeHoursLoop = storeHoursList.get(index);//start looking from today if (storeHoursLoop != null) { //check if its for today and we are within the store hours ZonedDateTime localDateTimeOpen = ZonedDateTime.now(TimeZone.getTimeZone(zoneID).toZoneId()).withHour(storeHoursLoop.getOpen().getHour()).withMinute(storeHoursLoop.getOpen().getMinute()).withSecond(0).plusDays(foundIndex).truncatedTo(ChronoUnit.SECONDS); ZonedDateTime localDateTimeClose = ZonedDateTime.now(TimeZone.getTimeZone(zoneID).toZoneId()).withHour(storeHoursLoop.getClose().getHour()).withMinute(storeHoursLoop.getClose().getMinute()).withSecond(0).minusMinutes(getStoreClosingOffset()).plusDays(foundIndex).truncatedTo(ChronoUnit.SECONDS); //we need to set the today offset based on the request time ZonedDateTime localStoreToday1 = null; if (todayOffset!=null) {// that means it has been passed in localStoreToday1 = ZonedDateTime.now(ZoneId.of(getRequestingSite().getTimeZoneID())).withHour(storeCurrentTime.getHour()).withMinute(storeCurrentTime.getMinute()).withSecond(0).plusMinutes(Long.parseLong(todayOffset)).truncatedTo(ChronoUnit.SECONDS); } if (i == 0){//store hours present for today storeOpenToday = localDateTimeOpen; storeCloseToday = localDateTimeClose; //should we set tommorrows offsets first even if its closed today StoreHours storeHourTomorrow = (index == 6) ? storeHoursList.get(0) : storeHoursList.get(index + 1); if (storeHourTomorrow!=null){ storeOpenTomorrow = ZonedDateTime.now(TimeZone.getTimeZone(zoneID).toZoneId()).withHour(storeHourTomorrow.getOpen().getHour()).withMinute(storeHourTomorrow.getOpen().getMinute()).withSecond(0).plusDays(1).truncatedTo(ChronoUnit.SECONDS); storeCloseTomorrow = ZonedDateTime.now(TimeZone.getTimeZone(zoneID).toZoneId()).withHour(storeHourTomorrow.getClose().getHour()).withMinute(storeHourTomorrow.getClose().getMinute()).minusMinutes(getStoreClosingOffset()).withSecond(0).plusDays(1).truncatedTo(ChronoUnit.SECONDS); } if (tomorrowTime !=null) { if (storeHourTomorrow!=null){ LocalTime localTimeTomorrow = LocalTime.parse(tomorrowTime); ZonedDateTime localDateTimeTomorrow = ZonedDateTime.now(TimeZone.getTimeZone(zoneID).toZoneId()).withHour(localTimeTomorrow.getHour()).withMinute(localTimeTomorrow.getMinute()).withSecond(0).plusDays(1).truncatedTo(ChronoUnit.SECONDS); // we need to set it only if its within store hours ? setTomorrow1CutoffTime(localDateTimeTomorrow); }//closed next day so cant have tomorrow buckets } if (storeCurrentTime.isBefore(localDateTimeClose) ){//could be before the store opens //found set the store hours setStoreOpen(localDateTimeOpen); setStoreClose(localDateTimeClose); //if(storeCurrentTime.isAfter(localDateTimeOpen)) { { setToday1CutoffTime(localStoreToday1);//set only for today since NA otherwise. Should we check if its after open time once ofseet si added? } break;//dont need to look anymore }else{ foundIndex++; index = (index == 6) ? index=0 : ++index; } }else {//could be tomorrow or any other day. if its tomorrow, we can still populate the tomorrow sub buckets based on the tommorow offset passed in if (i==1){// at this point we know we have the store open tomorrow if (tomorrowTime !=null){ LocalTime localTimeTomorrow = LocalTime.parse(tomorrowTime); ZonedDateTime localDateTimeTomorrow = ZonedDateTime.now(TimeZone.getTimeZone(zoneID).toZoneId()).withHour(localTimeTomorrow.getHour()).withMinute(localTimeTomorrow.getMinute()).withSecond(0).plusDays(1).truncatedTo(ChronoUnit.SECONDS); // we need to set it only if its within store hours ? setTomorrow1CutoffTime(localDateTimeTomorrow); } storeOpenTomorrow = ZonedDateTime.now(TimeZone.getTimeZone(zoneID).toZoneId()).withHour(storeHoursLoop.getOpen().getHour()).withMinute(storeHoursLoop.getOpen().getMinute()).withSecond(0).plusDays(1).truncatedTo(ChronoUnit.SECONDS); storeCloseTomorrow = ZonedDateTime.now(TimeZone.getTimeZone(zoneID).toZoneId()).withHour(storeHoursLoop.getClose().getHour()).withMinute(storeHoursLoop.getClose().getMinute()).minusMinutes(getStoreClosingOffset()).withSecond(0).plusDays(1).truncatedTo(ChronoUnit.SECONDS); } setStoreOpen(localDateTimeOpen); setStoreClose(localDateTimeClose); break; } }else{ foundIndex++; index = (index == 6) ? index=0 : ++index; storeHolidayToday=true; } } // now we can set a boolean whether the store is closed or open if (storeCurrentTime.isAfter(getStoreOpen()) && storeCurrentTime.isBefore(getStoreClose())) { storeOpenIndicator = true; }else{ storeOpenIndicator = false; } //are we passed store closed hours if (getStoreCloseToday() != null && storeCurrentTime.isAfter(getStoreCloseToday())) afterStoreHours = true; //we need to figure the next store open hours too if (storeOpenTomorrow != null && storeCloseTomorrow != null){ nextStoreOpen = storeOpenTomorrow; nextStoreClose = storeCloseTomorrow; }else{ //dstore horus are stored Monday to Sunday 0..6 in the list. day of week is 1..7 int actualDayOfWeek = localNow.getDayOfWeek().getValue(); int indexAfterTomorrow = 0; if (actualDayOfWeek==6) indexAfterTomorrow = 0; else if (actualDayOfWeek==7) indexAfterTomorrow = 1; else indexAfterTomorrow = actualDayOfWeek+1; int foundIndexNext = 2;//day after tomrrow days to add for (int i = 0; i < 5; i++) { StoreHours storeHoursNext = storeHoursList.get(indexAfterTomorrow);//start looking from day after if(storeHoursNext!=null){ nextStoreOpen = ZonedDateTime.now(TimeZone.getTimeZone(zoneID).toZoneId()).withHour(storeHoursNext.getOpen().getHour()).withMinute(storeHoursNext.getOpen().getMinute()).withSecond(0).plusDays(foundIndexNext).truncatedTo(ChronoUnit.SECONDS); nextStoreClose = ZonedDateTime.now(TimeZone.getTimeZone(zoneID).toZoneId()).withHour(storeHoursNext.getClose().getHour()).withMinute(storeHoursNext.getClose().getMinute()).withSecond(0).minusMinutes(getStoreClosingOffset()).plusDays(foundIndexNext).truncatedTo(ChronoUnit.SECONDS); break; } //else we need to look for the next day if (indexAfterTomorrow==6) indexAfterTomorrow=0; else indexAfterTomorrow=indexAfterTomorrow+1; foundIndexNext++; } } } public void initializeStoreTimeZoneValues(String TimeZoneOffset){ setStoreTimeZone(TimeZoneOffset); storeZoneOffset = ZoneOffset.ofTotalSeconds((int) (Float.valueOf(getStoreTimeZone())*60*60)); } }