package com.genpt.nsight.v4.controller; import com.genpt.nsight.NSightCache; import com.genpt.nsight.config.NSightProperties; import com.genpt.nsight.v1.model.Fault; import com.genpt.nsight.v1.model.HeaderResponse; import com.genpt.nsight.v1.model.Requestor; import com.genpt.nsight.v1.model.Tracking; 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.model.pubsub.InventoryEvent; import com.genpt.nsight.v4.model.pubsub.Action; import com.genpt.nsight.v4.service.ProductAvailabilityVerificationV4; import com.genpt.nsight.v4.service.impl.AsyncPubsubPublisher; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import javax.annotation.PostConstruct; import java.math.BigDecimal; import java.util.HashSet; import java.util.concurrent.Executors; @RestController @RequestMapping("/") @ConditionalOnExpression("${nsight.VerificationControllerV2.enabled:false}") public class InventoryVerificationController { @Autowired private NSightCache nSightCache; private static final Logger LOGGER = LoggerFactory.getLogger(InventoryVerificationController.class); @Autowired private ProductAvailabilityVerificationV4 productAvailabilityVerificationV4; @Autowired NSightProperties nSightProperties; @Autowired private AsyncPubsubPublisher asyncPubsubPublisher; @Value("${inventory.publishVerification}") private boolean publishVerification; @Autowired public void setProductAvailabilityVerificationV4(ProductAvailabilityVerificationV4 productAvailabilityVerificationV4) { this.productAvailabilityVerificationV4 = productAvailabilityVerificationV4; } @RequestMapping(value = "/InventoryVerification/v4", method = RequestMethod.POST) public com.genpt.nsight.v2.model.ProductAvailabilityResponse verifyInventory(@RequestBody com.genpt.nsight.v2.model.ProductAvailabilityRequest request) { AvailabilityServiceContextV4 availabilityServiceContextV4 = new AvailabilityServiceContextV4(); com.genpt.nsight.v2.model.ProductAvailabilityResponse productAvailabilityResponse = null; SplunkLogger splunkLogger = new SplunkLogger(request.getHeaderRequest()); try { //will need to transform the v2 to a v4 request com.genpt.nsight.v4.model.ProductAvailabilityRequest productAvailabilityRequest = new ProductAvailabilityRequest(); productAvailabilityRequest.setActionRequest(new ActionRequest()); productAvailabilityRequest.getActionRequest().setAction(new com.genpt.nsight.v4.model.Action()); productAvailabilityRequest.getActionRequest().getAction().setNeedAvailabilityDetails(true); productAvailabilityRequest.setHeaderRequest(request.getHeaderRequest()); productAvailabilityRequest.setDetailRequest(new DetailRequest()); productAvailabilityRequest.getDetailRequest().setInventoryRelationshipsRequested(new InventoryRelationshipsRequested()); productAvailabilityRequest.getDetailRequest().getInventoryRelationshipsRequested().setRequestingSite(true); productAvailabilityRequest.getDetailRequest().getInventoryRelationshipsRequested().setLocalStore(true); productAvailabilityRequest.getDetailRequest().setParts(new HashSet<>()); for (com.genpt.nsight.v1.model.Part partV2 : request.getDetailRequest().getParts()){ Part part = new Part(); part.setLineAbbrev(partV2.getLineAbbrev()); part.setPartNumber(partV2.getPartNumber()); productAvailabilityRequest.getDetailRequest().getParts().add(part); } availabilityServiceContextV4.setRequest(productAvailabilityRequest); ProductAvailabilityResponseFreePaid productAvailabilityResponseFreePaid = validateRequest(availabilityServiceContextV4, false, true); if (productAvailabilityResponseFreePaid!=null) { productAvailabilityResponse = new com.genpt.nsight.v2.model.ProductAvailabilityResponse(); productAvailabilityResponse.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())); productAvailabilityResponse.setHeaderResponse(headerResponse); productAvailabilityResponse.setTracking(new Tracking()); productAvailabilityResponse.getTracking().setIsSuccess(false); if (productAvailabilityResponseFreePaid.getTracking().getFault() != null) productAvailabilityResponse.getTracking().setFault(productAvailabilityResponseFreePaid.getTracking().getFault()); if (productAvailabilityResponseFreePaid.getTracking().getLog() != null) productAvailabilityResponse.getTracking().setLog(productAvailabilityResponseFreePaid.getTracking().getLog()); return productAvailabilityResponse; } else { productAvailabilityResponse = productAvailabilityVerificationV4.getProductAvailability(availabilityServiceContextV4); //before we return this response we need to publish it to pubsub com.genpt.nsight.v2.model.ProductAvailabilityResponse finalProductAvailabilityResponse = productAvailabilityResponse; // spawn a thread try { if(publishVerification) asyncPubsubPublisher.triggerPublish(finalProductAvailabilityResponse); } catch (Exception e) { throw new RuntimeException(e); } } } catch(Exception e) { LOGGER.error(splunkLogger.toString() + " Error In PartsAvailability, Message : {}, StackTrace: {} ", e.getMessage(), e.getStackTrace()); } return productAvailabilityResponse; } public ProductAvailabilityResponseFreePaid validateRequest(AvailabilityServiceContextV4 availabilityServiceContextV3, boolean isAggregate, boolean isVerification) { ProductAvailabilityResponseFreePaid productAvailabilityResponseFreePaid = null; Requestor requestor = availabilityServiceContextV3.getRequest().getHeaderRequest().getRequestor(); SplunkLogger splunkLogger = new SplunkLogger(availabilityServiceContextV3.getRequest().getHeaderRequest()); //retrieve all zipcodes if present boolean hasZips = false; //add the requesting store by default to the shiptosites //keep unique set of siteIDs in the Shipping Destinations HashSet shipToUniqueSet = new HashSet<>(); availabilityServiceContextV3.getShipToSitesMap().put(requestor.getRequestorIdentifier().getValue(), requestor.getRequestorIdentifier().getType()); String shipToSiteID = nSightCache.getAliasToSiteIdMap().get(requestor.getRequestorIdentifier().getType()+"|"+requestor.getRequestorIdentifier().getValue()); shipToUniqueSet.add(shipToSiteID); // if the calling store is a non napa store, we know that we need to get data from store endpoint. we need to make sure we have all the //required data in site table for doing that. boolean isOnlyLocalStore = false; if (availabilityServiceContextV3.getRequest().getDetailRequest().getInventoryRelationshipsRequested().isLocalStore() && availabilityServiceContextV3.getRequest().getDetailRequest().getInventoryRelationshipsRequested().isServingDC()==false && availabilityServiceContextV3.getRequest().getDetailRequest().getInventoryRelationshipsRequested().isAllOtherDCs()==false && availabilityServiceContextV3.getRequest().getDetailRequest().getInventoryRelationshipsRequested().isAllSuppliers()==false && availabilityServiceContextV3.getRequest().getDetailRequest().getInventoryRelationshipsRequested().getOtherSites() == null && availabilityServiceContextV3.getRequest().getDetailRequest().getInventoryRelationshipsRequested().getOtherRelationShips() == null) { isOnlyLocalStore = true; } if (isOnlyLocalStore) { if (shipToSiteID != null) { SiteDTO siteDTO = nSightCache.getSiteIdToSiteMap().get(shipToSiteID); //if its a third party store if (siteDTO != null && siteDTO.getPosType() != null && (siteDTO.getPosType().compareToIgnoreCase("NON_NAPA") == 0 || siteDTO.getPosType().compareToIgnoreCase("NON NAPA") == 0)) { //make sure we have the pos password and url if (((availabilityServiceContextV3.getRequest().getHeaderRequest().getResponder().getSecurity() == null || availabilityServiceContextV3.getRequest().getHeaderRequest().getResponder().getSecurity().getUserCredentials() == null) && siteDTO.getPosPassword() == null) || siteDTO.getPosURL() == null) { productAvailabilityResponseFreePaid = availabilityServiceContextV3.getProductAvailabilityResponseFreePaidTemplate(availabilityServiceContextV3); Tracking tracking = new Tracking(); tracking.setIsSuccess(Boolean.FALSE); tracking.setFault(Fault.builder().code("2001").message("Invalid PartsAvailability Request - Credentials/URL Missing in Request or Site Table").build()); LOGGER.error(splunkLogger.toString() + " Invalid PartsAvailability Request, Credentials/URL Missing in Request or Site Table, Error Code: 2001"); productAvailabilityResponseFreePaid.setTracking(tracking); } } } } if ((availabilityServiceContextV3.getRequest().getActionRequest().getAction().getNeedPricing() && (availabilityServiceContextV3.getRequest().getHeaderRequest().getResponder().getSecurity() == null || availabilityServiceContextV3.getRequest().getHeaderRequest().getResponder().getSecurity().getUserCredentials()==null)) || (availabilityServiceContextV3.getRequest().getActionRequest().getAction().getNeedPricing() && (availabilityServiceContextV3.getRequest().getHeaderRequest().getResponder().getSecurity().getUserCredentials().getPassword()==null || availabilityServiceContextV3.getRequest().getHeaderRequest().getResponder().getSecurity().getUserCredentials().getPassword().isEmpty()))){ productAvailabilityResponseFreePaid = availabilityServiceContextV3.getProductAvailabilityResponseFreePaidTemplate(availabilityServiceContextV3); Tracking tracking = new Tracking(); tracking.setIsSuccess(Boolean.FALSE); tracking.setFault(Fault.builder().code("2001").message("Invalid PartsAvailability Request - User Credentials must be populated if Pricing is required").build()); LOGGER.error(splunkLogger.toString() + " Invalid PartsAvailability Request, Error Code: 2001"); productAvailabilityResponseFreePaid.setTracking(tracking); } if (availabilityServiceContextV3.getRequest().getDetailRequest().getParts().size() == 0){ productAvailabilityResponseFreePaid = availabilityServiceContextV3.getProductAvailabilityResponseFreePaidTemplate(availabilityServiceContextV3); Tracking tracking = new Tracking(); tracking.setIsSuccess(Boolean.FALSE); tracking.setFault(Fault.builder().code("2001").message("Invalid PartsAvailability Request - Must contain atleast one part").build()); LOGGER.error(splunkLogger.toString() + " Invalid PartsAvailability Request, Error Code: 2001"); productAvailabilityResponseFreePaid.setTracking(tracking); } if (availabilityServiceContextV3.getRequest().getDetailRequest().getParts().size() > 100){ productAvailabilityResponseFreePaid = availabilityServiceContextV3.getProductAvailabilityResponseFreePaidTemplate(availabilityServiceContextV3); Tracking tracking = new Tracking(); tracking.setIsSuccess(Boolean.FALSE); tracking.setFault(Fault.builder().code("2001").message("Invalid PartsAvailability Request - Maximum parts allowed is 100").build()); LOGGER.error(splunkLogger.toString() + " Invalid PartsAvailability Request, Error Code: 2001"); productAvailabilityResponseFreePaid.setTracking(tracking); } if (availabilityServiceContextV3.getRequest().getDetailRequest().getShippingDestination() != null) { if (availabilityServiceContextV3.getRequest().getDetailRequest().getShippingDestination().getShippingDestinationIdentifiers()!= null && availabilityServiceContextV3.getRequest().getDetailRequest().getShippingDestination().getShippingDestinationIdentifiers().size() > 5) { productAvailabilityResponseFreePaid = availabilityServiceContextV3.getProductAvailabilityResponseFreePaidTemplate(availabilityServiceContextV3); Tracking tracking = new Tracking(); tracking.setIsSuccess(Boolean.FALSE); tracking.setFault(Fault.builder().code("2001").message("Invalid PartsAvailability Request, Maximum of 5 Shipping Destination Identifiers can be specified.").build()); LOGGER.error(splunkLogger.toString()+ " Invalid PartsAvailability Request, Maximum of 5 Shipping Destination Identifiers can be specified. Error Code: 2001"); productAvailabilityResponseFreePaid.setTracking(tracking); }else if (availabilityServiceContextV3.getRequest().getDetailRequest().getShippingDestination() !=null && availabilityServiceContextV3.getRequest().getDetailRequest().getShippingDestination().getShippingDestinationIdentifiers()!= null){ for (com.genpt.nsight.v2.model.ShippingDestinationIdentifier shippingDestinationIdentifier : availabilityServiceContextV3.getRequest().getDetailRequest().getShippingDestination().getShippingDestinationIdentifiers()) { if (shippingDestinationIdentifier.getName() != null && shippingDestinationIdentifier.getValue() != null && shippingDestinationIdentifier.getName().trim().length() != 0 && shippingDestinationIdentifier.getValue().trim().length()!=0) { if (shippingDestinationIdentifier.getName().compareToIgnoreCase("Zip Code") == 0) { hasZips = true;//add it to the list String zipCode = shippingDestinationIdentifier.getValue(); if (zipCode!=null) zipCode = zipCode.replaceAll("\\s", ""); if (zipCode != null && (zipCode.length() == 5 || zipCode.length() == 6)) { availabilityServiceContextV3.getZipCodesSet().add(zipCode); } } else {//its a ship to site /// we need to add only unique site IDS shipToSiteID = nSightCache.getAliasToSiteIdMap().get(shippingDestinationIdentifier.getName() + "|" + shippingDestinationIdentifier.getValue()); if (!shipToUniqueSet.contains(shipToSiteID)) {//add it availabilityServiceContextV3.getShipToSitesMap().put(shippingDestinationIdentifier.getValue(), shippingDestinationIdentifier.getName()); shipToUniqueSet.add(shipToSiteID); } } }else { productAvailabilityResponseFreePaid = availabilityServiceContextV3.getProductAvailabilityResponseFreePaidTemplate(availabilityServiceContextV3); Tracking tracking = new Tracking(); tracking.setIsSuccess(Boolean.FALSE); tracking.setFault(Fault.builder().code("2001").message("Invalid PartsAvailability Request, Shipping Destination Identifiers name and value must be specified.").build()); LOGGER.error(splunkLogger.toString()+ " Invalid PartsAvailability Request, Shipping Destination Identifiers name and value must be specified.. Error Code: 2001"); productAvailabilityResponseFreePaid.setTracking(tracking); } } } } //validate the zipcode if (Boolean.TRUE.equals(hasZips) && availabilityServiceContextV3.getZipCodesSet().size()==0 ){ productAvailabilityResponseFreePaid = availabilityServiceContextV3.getProductAvailabilityResponseFreePaidTemplate(availabilityServiceContextV3); Tracking tracking = new Tracking(); tracking.setIsSuccess(Boolean.FALSE); tracking.setFault(Fault.builder().code("2001").message("Invalid PartsAvailability Request - Incorrect ZipCode").build()); LOGGER.error(splunkLogger.toString()+ " Invalid PartsAvailability Request,Incorrect ZipCode. Error Code: 2001"); productAvailabilityResponseFreePaid.setTracking(tracking); } if (Boolean.TRUE.equals(isAggregate) && availabilityServiceContextV3.getRequest().getDetailRequest().getShippingDestination() != null){ productAvailabilityResponseFreePaid = availabilityServiceContextV3.getProductAvailabilityResponseFreePaidTemplate(availabilityServiceContextV3); Tracking tracking = new Tracking(); tracking.setIsSuccess(Boolean.FALSE); tracking.setFault(Fault.builder().code("2001").message("Invalid PartsAvailability Request, ShippingDestination Cannot be specified").build()); LOGGER.error(splunkLogger.toString()+ " Invalid PartsAvailability Request, ShippingDestination Cannot be specified, Error Code: 2001"); productAvailabilityResponseFreePaid.setTracking(tracking); } // need to make sure we have availability set to true for Aggregates if (Boolean.TRUE.equals(isAggregate) && Boolean.FALSE.equals(availabilityServiceContextV3.getRequest().getActionRequest().getAction().getNeedDeliveryEstimateCutOffTimes())){ productAvailabilityResponseFreePaid = availabilityServiceContextV3.getProductAvailabilityResponseFreePaidTemplate(availabilityServiceContextV3); Tracking tracking = new Tracking(); tracking.setIsSuccess(Boolean.FALSE); tracking.setFault(Fault.builder().code("2001").message("Invalid PartsAvailability Request").build()); LOGGER.error(splunkLogger.toString()+ " Invalid PartsAvailability Request, needDeliveryEstimateCutOffTimes cannot be false. Error Code: 2001"); productAvailabilityResponseFreePaid.setTracking(tracking); } //make sure need availability is always set to true if (Boolean.FALSE.equals(availabilityServiceContextV3.getRequest().getActionRequest().getAction().getNeedProductQuantity())) { productAvailabilityResponseFreePaid = availabilityServiceContextV3.getProductAvailabilityResponseFreePaidTemplate(availabilityServiceContextV3); Tracking tracking = new Tracking(); tracking.setIsSuccess(Boolean.FALSE); tracking.setFault(Fault.builder().code("2001").message("Invalid PartsAvailability Request").build()); LOGGER.error(splunkLogger.toString()+ " Invalid PartsAvailability Request, needProductQuantity cannot be false. Error Code: 2001"); productAvailabilityResponseFreePaid.setTracking(tracking); } else if (!nSightCache.getAliasToSiteIdMap().containsKey(requestor.getRequestorIdentifier().getType() + "|" + requestor.getRequestorIdentifier().getValue())) { //before we send this error back, check if its a TAM or JDE client //since they would request data for a inactive site if (availabilityServiceContextV3.getApplicationID()==null){ productAvailabilityResponseFreePaid = availabilityServiceContextV3.getProductAvailabilityResponseFreePaidTemplate(availabilityServiceContextV3); Tracking tracking = new Tracking(); tracking.setIsSuccess(Boolean.FALSE); tracking.setFault(Fault.builder().code("3003").message("Invalid Requestor Application for " + requestor.getRequestorIdentifier().getType() + " and Alias Value " + requestor.getRequestorIdentifier().getValue()).build()); LOGGER.error(splunkLogger.toString()+ "Invalid Requestor Application , Error Code: 3003"); productAvailabilityResponseFreePaid.setTracking(tracking); }else { if (availabilityServiceContextV3.getApplicationID().equalsIgnoreCase("JDE") || availabilityServiceContextV3.getApplicationID().equalsIgnoreCase("TAMS") || isVerification) { //check in inactive Map if (!nSightCache.getInactiveAliasToSiteIdMap().containsKey(requestor.getRequestorIdentifier().getType() + "|" + requestor.getRequestorIdentifier().getValue())) { productAvailabilityResponseFreePaid = availabilityServiceContextV3.getProductAvailabilityResponseFreePaidTemplate(availabilityServiceContextV3); Tracking tracking = new Tracking(); tracking.setIsSuccess(Boolean.FALSE); tracking.setFault(Fault.builder().code("3003").message("Invalid Site for Alias Name " + requestor.getRequestorIdentifier().getType() + " and Alias Value " + requestor.getRequestorIdentifier().getValue()).build()); LOGGER.error(splunkLogger.toString() + " Invalid Site for Alias Name , Error Code: 3003"); productAvailabilityResponseFreePaid.setTracking(tracking); } } else { productAvailabilityResponseFreePaid = availabilityServiceContextV3.getProductAvailabilityResponseFreePaidTemplate(availabilityServiceContextV3); Tracking tracking = new Tracking(); tracking.setIsSuccess(Boolean.FALSE); tracking.setFault(Fault.builder().code("3003").message("Invalid or Inactive Site for Alias Name " + requestor.getRequestorIdentifier().getType() + " and Alias Value " + requestor.getRequestorIdentifier().getValue()).build()); LOGGER.error(splunkLogger.toString() + " Invalid or Inactive Site for Alias Name , Error Code: 3003"); productAvailabilityResponseFreePaid.setTracking(tracking); } } } return productAvailabilityResponseFreePaid; } }