package com.genpt.nsight.v4.service.impl; import static java.time.temporal.ChronoUnit.MILLIS; import com.datastax.driver.core.*; import com.genpt.nsight.NSightCache; import com.genpt.nsight.b2b.model.MultiPart.MultiPartInquiryRequestType; import com.genpt.nsight.config.NSightProperties; import com.genpt.nsight.v1.SplunkLogger; import com.genpt.nsight.v1.model.*; import com.genpt.nsight.v1.model.POSService.POSServiceResponse; import com.genpt.nsight.v1.model.POSService.POSServiceResponseData; import com.genpt.nsight.v1.model.POSService.PriceAvailabilityRequest; import com.genpt.nsight.v1.model.POSService.ServiceRequest; import com.genpt.nsight.v1.model.dto.SiteDTO; import com.genpt.nsight.v3.service.ConfigManagementService; import com.genpt.nsight.v4.AvailabilityServiceContextV4; import com.genpt.nsight.v4.model.DetailRequest; import com.genpt.nsight.v4.model.InventoryRelationshipsRequested; import com.genpt.nsight.v4.model.Part; import com.genpt.nsight.v4.model.inventory.availability.*; import com.genpt.nsight.v4.service.InventoryServiceV4; import com.genpt.nsight.v4.service.POSService; import com.genpt.nsight.v4.service.inventory.AsyncAvailabilityClient; import com.genpt.nsight.v4.service.inventory.AvailabilityService; import com.google.common.base.Stopwatch; import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.*; import java.time.Duration; import java.util.concurrent.*; import java.util.stream.Stream; 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.stereotype.Service; import javax.annotation.PostConstruct; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import java.math.BigDecimal; import java.util.*; import java.util.stream.Collectors; @Service("InventoryServiceV4") public class InventoryServiceV4Impl implements InventoryServiceV4 { public static final HashSet ALL_SUPPLIERS = new HashSet<>(Arrays.asList("ALL")); @Autowired private Session session; @Autowired NSightCache nSightCache; private Map preparedStatementMap; @Autowired ConfigManagementService configManagementService; private Tracking tracking = new Tracking(); private static final Logger LOGGER = LoggerFactory.getLogger(InventoryServiceV4Impl.class); private ListeningExecutorService posServiceExecutor; JAXBContext context = null; JAXBContext rpmContext = null; JAXBContext uapContext = null; @Autowired NSightProperties nSightProperties; @Autowired AsyncAvailabilityClient asyncAvailabilityClient; private static long availabilityTimeout; @Value("${inventory.availabilityServiceTimeout}") public void setAvailabilityTimeout(long availabilityTimeout){ this.availabilityTimeout=availabilityTimeout; } @PostConstruct public void init() throws JAXBException { preparedStatementMap = new HashMap<>(); PreparedStatement primaryDCInventoryStmt = session.prepare( "select part_number, line_abbrev, site_identifier, available_quantity, data_as_of_ts, in_transit_quantity, in_transit_ts, increment_sell_quantity, max_stock_quantity, min_sell_quantity, min_stock_quantity, on_hand_quantity,on_order_quantity, on_order_quantity, on_order_ts, part_description, unit_of_measure_designator from dc_inventory where part_number = ? and line_abbrev = ? and site_identifier = ?;"); primaryDCInventoryStmt.setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM); PreparedStatement primaryUAPDCInventoryCodeStmt = session.prepare( "select part_number, line_abbrev, site_identifier, inventory_code, data_as_of_ts from uap_dc_inventory_code where part_number = ? and line_abbrev = ? and site_identifier = ?;"); primaryDCInventoryStmt.setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM); //these are the prepared statements for Details Service //Statement for single DC lookup PreparedStatement anySupplierInventoryStmt = session.prepare( "select part_number, line_abbrev, site_identifier, available_quantity, data_as_of_ts, in_transit_quantity, in_transit_ts, increment_sell_quantity, max_stock_quantity, min_sell_quantity, min_stock_quantity, on_hand_quantity,on_order_quantity, on_order_quantity, on_order_ts, part_description, unit_of_measure_designator,order_since_last_update_quantity from supplier_inventory where part_number = ? and line_abbrev = ? and site_identifier = ?;"); anySupplierInventoryStmt.setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM); PreparedStatement anyDCInventoryStmt = session.prepare( "select part_number, line_abbrev, site_identifier, available_quantity, data_as_of_ts, in_transit_quantity, in_transit_ts, increment_sell_quantity, max_stock_quantity, min_sell_quantity, min_stock_quantity, on_hand_quantity,on_order_quantity, on_order_quantity, on_order_ts, part_description, unit_of_measure_designator from dc_inventory where part_number = ? and line_abbrev = ? and site_identifier = ?;"); anyDCInventoryStmt.setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM); PreparedStatement allDCInventoryStmt = session.prepare( "select part_number, line_abbrev, site_identifier, available_quantity, data_as_of_ts, in_transit_quantity, in_transit_ts, increment_sell_quantity, max_stock_quantity, min_sell_quantity, min_stock_quantity, on_hand_quantity,on_order_quantity, on_order_quantity, on_order_ts, part_description, unit_of_measure_designator from dc_inventory where part_number = ? and line_abbrev = ?"); allDCInventoryStmt.setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM); PreparedStatement supplierInventoryStmt = session.prepare( "select part_number, line_abbrev, site_identifier, available_quantity, data_as_of_ts, in_transit_quantity, in_transit_ts, increment_sell_quantity, max_stock_quantity, min_sell_quantity, min_stock_quantity, on_hand_quantity,on_order_quantity, on_order_quantity, on_order_ts, part_description, unit_of_measure_designator, order_since_last_update_quantity from supplier_inventory where part_number = ? and line_abbrev = ?;"); supplierInventoryStmt.setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM); PreparedStatement storeInventoryStmt = session.prepare( "select part_number, line_abbrev, site_identifier, available_quantity, data_as_of_ts, in_transit_quantity, in_transit_ts, increment_sell_quantity, max_stock_quantity, min_sell_quantity, min_stock_quantity, on_hand_quantity,on_order_quantity, on_order_quantity, on_order_ts, part_description, unit_of_measure_designator from store_inventory where part_number = ? and line_abbrev = ? and store_partition_key = ? and site_identifier = ?;"); storeInventoryStmt.setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM); //these are the prepared statements for aggregate services PreparedStatement anySupplierInventoryStmt_aggregate = session.prepare( "select part_number, line_abbrev, site_identifier, available_quantity, order_since_last_update_quantity from supplier_inventory where part_number = ? and line_abbrev = ? and site_identifier = ?;"); anySupplierInventoryStmt_aggregate.setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM); PreparedStatement primaryDCInventoryStmt_aggregate = session.prepare( "select part_number, line_abbrev, site_identifier, available_quantity from dc_inventory where part_number = ? and line_abbrev = ? and site_identifier = ?;"); primaryDCInventoryStmt_aggregate.setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM); PreparedStatement anyDCInventoryStmt_aggregate = session.prepare( "select part_number, line_abbrev, site_identifier, available_quantity from dc_inventory where part_number = ? and line_abbrev = ? and site_identifier = ?;"); primaryDCInventoryStmt_aggregate.setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM); PreparedStatement allDCInventoryStmt_aggregate = session.prepare( "select part_number, line_abbrev, site_identifier, available_quantity from dc_inventory where part_number = ? and line_abbrev = ?"); allDCInventoryStmt_aggregate.setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM); PreparedStatement supplierInventoryStmt_aggregate = session.prepare( "select part_number, line_abbrev, site_identifier, available_quantity, order_since_last_update_quantity from supplier_inventory where part_number = ? and line_abbrev = ?;"); supplierInventoryStmt_aggregate.setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM); PreparedStatement storeInventoryStmt_aggregate = session.prepare( "select part_number, line_abbrev, site_identifier, available_quantity from store_inventory where part_number = ? and line_abbrev = ? and store_partition_key = ? and site_identifier = ?;"); storeInventoryStmt_aggregate.setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM); //detail PS preparedStatementMap.put("PrimaryDC", primaryDCInventoryStmt); preparedStatementMap.put("PrimaryUAPDCInventoryCode", primaryUAPDCInventoryCodeStmt); preparedStatementMap.put("AllOtherDCs", allDCInventoryStmt); preparedStatementMap.put("Supplier", supplierInventoryStmt); preparedStatementMap.put("Store", storeInventoryStmt); preparedStatementMap.put("AnyDC", anyDCInventoryStmt); preparedStatementMap.put("AnySupplier", anySupplierInventoryStmt); //Aggregate PS preparedStatementMap.put("PrimaryDC_Aggregate", primaryDCInventoryStmt_aggregate); preparedStatementMap.put("AllOtherDCs_Aggregate", allDCInventoryStmt_aggregate); preparedStatementMap.put("Supplier_Aggregate", supplierInventoryStmt_aggregate); preparedStatementMap.put("Store_Aggregate", storeInventoryStmt_aggregate); preparedStatementMap.put("AnyDC_Aggregate", anyDCInventoryStmt_aggregate); preparedStatementMap.put("AnySupplier_Aggregate", anySupplierInventoryStmt_aggregate); ExecutorService workerPool = new ThreadPoolExecutor(5, nSightProperties.getPosServiceThreads(), 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>(5000), new ThreadFactoryBuilder().setNameFormat("pos-service-thread-%d").build(), (r, executor) -> { throw new RejectedExecutionException("Request rejected from queue");}); posServiceExecutor = MoreExecutors.listeningDecorator(workerPool); context = JAXBContext.newInstance(ServiceRequest.class); rpmContext = JAXBContext.newInstance(PriceAvailabilityRequest.class); uapContext = JAXBContext.newInstance(MultiPartInquiryRequestType.class); } @Override public void preparePartList(AvailabilityServiceContextV4 availabilityServiceContextV3) { Set inputPartsSet = new HashSet<>( availabilityServiceContextV3.getRequest().getDetailRequest().getParts()); final Map> virtualPart2ParentPartMap = new HashMap<>(); final List virtualPartListForInput = new ArrayList<>(); final Map parentPartMap = new HashMap<>(); final Map kitComponentMap = new HashMap<>(); final Map inputParts = new HashMap<>(); for (Iterator inputPartsIterator = inputPartsSet.iterator(); inputPartsIterator.hasNext(); ) { com.genpt.nsight.v4.model.Part part = inputPartsIterator.next(); //for verification we dont need to check if its a vartual kit String fullPartNumber = part.getLineAbbrev() + "-" + part.getPartNumber(); inputParts.put(fullPartNumber, part); boolean isNotVerification = !availabilityServiceContextV3.isVerification(); boolean isB2B = availabilityServiceContextV3.getRequest().getHeaderRequest().getRequestor().getRequestorType() .compareToIgnoreCase("B2BLegacy") == 0 ? true : false; if (!isB2B) { if (isNotVerification) { ProductKit productKit = null; if (availabilityServiceContextV3.getRequestingSite().getCountry() != null && availabilityServiceContextV3.getRequestingSite().getCountry().compareToIgnoreCase("CAN") == 0) { productKit = nSightCache.getProductKitMapCA().get(fullPartNumber); } else { productKit = nSightCache.getProductKitMapUS().get(fullPartNumber); } if (productKit != null) { productKit.getKitComponents().forEach(kitComponent -> { com.genpt.nsight.v4.model.Part virtualPart = new com.genpt.nsight.v4.model.Part(); virtualPart.setLineAbbrev(kitComponent.getLineAbbrev()); virtualPart.setPartNumber(kitComponent.getPartNumber()); virtualPartListForInput.add(virtualPart); String virtualPartFullLineNumber = virtualPart.getLineAbbrev() + "-" + virtualPart.getPartNumber(); //get the existing set of VirtualKits for this part Set parentKeysSet = virtualPart2ParentPartMap.get(virtualPartFullLineNumber); if (parentKeysSet == null) { parentKeysSet = new HashSet(); } parentKeysSet.add(fullPartNumber); virtualPart2ParentPartMap.put(virtualPartFullLineNumber, parentKeysSet); kitComponentMap.put(virtualPartFullLineNumber, kitComponent); }); parentPartMap.put(fullPartNumber, part); part.setProductKit(productKit); inputPartsIterator.remove(); } } } } if (virtualPartListForInput != null && virtualPartListForInput.size() > 0) { inputPartsSet.addAll(virtualPartListForInput); availabilityServiceContextV3.setVirtualPart2ParentPartMap(virtualPart2ParentPartMap); availabilityServiceContextV3.setParentPartMap(parentPartMap); availabilityServiceContextV3.setKitComponentMap(kitComponentMap); } availabilityServiceContextV3.setPartSet(inputPartsSet); availabilityServiceContextV3.setInputParts(inputParts); } @Override public ResultSetFuture getInventory(AvailabilityServiceContextV4 availabilityServiceContextV3, String type, String partNumber, String lineAbbrev, String storePartKey, String siteId, String posType) { PreparedStatement preparedStatement = preparedStatementMap.get(type); BoundStatement boundStatement; boolean callGetInventory = true; //do a check to make only one request for a part and siteID combination if (siteId != null) {//siteid is null for allsuppliers and allDCs if (availabilityServiceContextV3.getPartRelatedSiteSet().contains(partNumber + lineAbbrev + siteId) && !type.startsWith("PrimaryUAPDCInventoryCode")) { callGetInventory = false; } else { availabilityServiceContextV3.getPartRelatedSiteSet().add(partNumber + lineAbbrev + siteId); } } if (callGetInventory) { if (type.startsWith("PrimaryDC") || type.startsWith("PrimaryUAPDCInventoryCode") || type.startsWith("AnyDC") || type.startsWith("AnySupplier")) { boundStatement = preparedStatement.bind(partNumber, lineAbbrev, UUID.fromString(siteId)); } else if (type.startsWith("Store")) { if (storePartKey != null || posType == null || (posType != null && posType.compareToIgnoreCase("NON_NAPA") != 0)) { boundStatement = preparedStatement.bind(partNumber, lineAbbrev, storePartKey, UUID.fromString(siteId)); } else { LOGGER.info("Store Partition Key is null or is a non NAPA Store: {} ", siteId); boundStatement = null; } } else { boundStatement = preparedStatement.bind(partNumber, lineAbbrev); } if (boundStatement != null) { return session.executeAsync(boundStatement); } else { return null; } } else { return null; } } private List retrieveRelatedSiteDTOs(AvailabilityServiceContextV4 serviceContext){ //get the set of related sites Set relatedSiteIds = serviceContext.getRelatedSites().stream().map(rs -> rs.getSiteId()) .filter(siteID -> siteID != null).collect(Collectors.toSet()); //first get the site id's List siteDTOs = nSightCache.getSiteIdToSiteMap().entrySet().stream() .filter(stringSiteDTOEntry -> relatedSiteIds.contains(stringSiteDTOEntry.getKey())).map(Map.Entry::getValue) .collect(Collectors.toList()); return siteDTOs; } private Set populateSupplierLocations(InventoryRelationshipsRequested relationshipsRequested,List siteDTOs) { Set supplierLocations = null; List supplierSiteIdentifierList = new ArrayList<>(); // this probably would go into @createSupplierRequestTask if (!relationshipsRequested.isAllSuppliers()) { siteDTOs.stream().forEach(siteDTO -> supplierSiteIdentifierList.addAll( siteDTO.getSiteIdentifierList().stream().filter( siteIdentifier -> siteIdentifier.getName().compareToIgnoreCase("Supplier Abbreviation Location") == 0).collect(Collectors.toList()))); supplierLocations = supplierSiteIdentifierList.stream().map(siteIdentifier -> siteIdentifier.getValue()) .collect(Collectors.toSet()); } return supplierLocations; } private Set populateDCLocations( InventoryRelationshipsRequested relationshipsRequested,List siteDTOs,AvailabilityServiceContextV4 availabilityServiceContextV4){ Set dcLocations = null; List dcSiteIdentifierList = new ArrayList<>(); // this probably would go into @createDCRequestTask if (!relationshipsRequested.isAllOtherDCs()) { //we also need the serving DC added in this DC list if(availabilityServiceContextV4.getRequest().getDetailRequest().getInventoryRelationshipsRequested().isServingDC() && availabilityServiceContextV4.getPrimaryDC()!=null) siteDTOs.add(nSightCache.getSiteIdToSiteMap().get(availabilityServiceContextV4.getPrimaryDC().getSiteId())); siteDTOs.stream().forEach(siteDTO -> dcSiteIdentifierList.addAll(siteDTO.getSiteIdentifierList().stream() .filter(siteIdentifier -> siteIdentifier.getName().compareToIgnoreCase("DC Abbreviation Code") == 0) .collect(Collectors.toList()))); dcLocations = dcSiteIdentifierList.stream().map(siteIdentifier -> siteIdentifier.getValue()) .collect(Collectors.toSet()); } return dcLocations; } private Set populateStoreLocations( InventoryRelationshipsRequested relationshipsRequested,List siteDTOs){ Set storeLocations = null; List storeSiteIdentifierList = new ArrayList<>(); //now get the 9 digit store numbers, DC Abbrevs and supplier locations siteDTOs.stream().forEach(siteDTO -> storeSiteIdentifierList.addAll(siteDTO.getSiteIdentifierList().stream() .filter(siteIdentifier -> siteIdentifier.getName().compareToIgnoreCase("9 Digit Store Number") == 0) .collect(Collectors.toList()))); storeLocations = storeSiteIdentifierList.stream().map(siteIdentifier -> siteIdentifier.getValue()) .collect(Collectors.toSet()); return storeLocations; } @Override public ListenableFuture createAvailabilityCallsMultiPart(AvailabilityServiceContextV4 serviceContext){ SplunkLogger splunkLogger = new SplunkLogger(serviceContext.getRequest().getHeaderRequest()); long start = System.currentTimeMillis(); String correlationId = serviceContext.getCorrelationID(); String clientId = serviceContext.getApplicationID(); String country = serviceContext.getRequest().getHeaderRequest().getCountryCode(); List siteDTOs = retrieveRelatedSiteDTOs(serviceContext); InventoryRelationshipsRequested relationshipsRequested = serviceContext.getRequest() .getDetailRequest().getInventoryRelationshipsRequested(); //create the list of products and list of locations List products = serviceContext.getPartSet().stream().flatMap(part -> Stream.of(createProduct(part))).collect(Collectors.toList()); //create the list of locations Optional> storeLocations = Optional.ofNullable(populateStoreLocations(relationshipsRequested, siteDTOs)); Optional> dcLocations = Optional.ofNullable(populateDCLocations(relationshipsRequested, siteDTOs,serviceContext)); Optional> supplierLocations = Optional.ofNullable(populateSupplierLocations(relationshipsRequested, siteDTOs)); List locations = new ArrayList<>(); if(storeLocations.isPresent()) locations = createLocationList("Store",storeLocations); if(dcLocations.isPresent()) locations.addAll(createLocationList("DC",dcLocations)); if(supplierLocations.isPresent()) locations.addAll(createLocationList("Supplier",supplierLocations)); // create the multipart request InventoryRequestMultiProduct request = new InventoryRequestMultiProduct(); request.setLocations(locations); request.setProducts(products); request.setAllDCs(relationshipsRequested.isAllOtherDCs()); request.setAllSuppliers(relationshipsRequested.isAllSuppliers()); Stopwatch sw=Stopwatch.createStarted(); SettableFuture gcpMultiProductFuture = SettableFuture.create(); asyncAvailabilityClient .callMultiProductAvailability(request,splunkLogger,serviceContext.getRequest().getActionRequest().getAction().getNeedAvailabilityDetails(), correlationId,clientId,country) .timeout(Duration.of(availabilityTimeout, MILLIS)) .onErrorReturn(new InventoryResponseMultiProduct()) .subscribe(response -> { LOGGER.info(splunkLogger.toString() +" createAvailabilityCallsMultiProduct: Executed requests in {}",sw.stop()); gcpMultiProductFuture.set(response); }); return gcpMultiProductFuture; } private static Product createProduct(Part part){ Product product = new Product(); product.setProductNbr(part.getPartNumber()); product.setProductCd(part.getLineAbbrev()); return product; } private static LocationV2 createLocation(String locationId, String locationType){ LocationV2 locationV2 = new LocationV2(); locationV2.setType(locationType); locationV2.setIdentifier(locationId); return locationV2; } private static List createLocationList(String locationType, Optional> locations){ return Stream.of(locations.get().stream() .flatMap(s -> Stream.of(createLocation(s, locationType))) .collect(Collectors.toList())) .flatMap(List::stream) .collect(Collectors.toList()); } @Override public ListenableFuture> createAvailabilityCallsAsync(AvailabilityServiceContextV4 serviceContext){ SplunkLogger splunkLogger = new SplunkLogger(serviceContext.getRequest().getHeaderRequest()); long start = System.currentTimeMillis(); String correlationId = serviceContext.getCorrelationID(); String clientId = serviceContext.getApplicationID(); String country = serviceContext.getRequest().getHeaderRequest().getCountryCode(); List siteDTOs = retrieveRelatedSiteDTOs(serviceContext); InventoryRelationshipsRequested relationshipsRequested = serviceContext.getRequest() .getDetailRequest().getInventoryRelationshipsRequested(); Set storeLocations =populateStoreLocations(relationshipsRequested,siteDTOs); Set dcLocations =populateDCLocations(relationshipsRequested,siteDTOs,serviceContext); Set supplierLocations =populateSupplierLocations(relationshipsRequested,siteDTOs); //lets make the calls using the async client to BT List requests = serviceContext.getPartSet() .stream() .flatMap(part -> Stream.of( createStoreRequestTask(serviceContext, part, correlationId, clientId, country, storeLocations), createDCRequestTask(serviceContext, part, relationshipsRequested, correlationId, clientId, country, dcLocations), createSupplierRequestTask( serviceContext, part, relationshipsRequested, correlationId, clientId, country, supplierLocations))).collect(Collectors.toList()); Stopwatch sw=Stopwatch.createStarted(); SettableFuture> gcpInventoryFutures = SettableFuture.create(); asyncAvailabilityClient .sendAllRequests(requests,splunkLogger) .collectList() .timeout(Duration.of(availabilityTimeout, MILLIS)) .onErrorReturn(ImmutableList.of()) .subscribe(response -> { LOGGER.debug(splunkLogger.toString() +" createAvailabilityCallsAsync: Executed requests in {}, got {} responses",sw.stop(), response.size()); gcpInventoryFutures.set(response); }); LOGGER.debug(splunkLogger.toString() + " createAvailabilityCallsAsync to GCP sending for all requests in {} ms", System.currentTimeMillis()-start); return gcpInventoryFutures; } private static AvailabilityService createStoreRequestTask(AvailabilityServiceContextV4 availabilityServiceContextV3, Part part, String correlationId, String clientId, String country, Set storeLocations) { return new AvailabilityService(correlationId, clientId, country, "Store", part.getLineAbbrev(), part.getPartNumber(), storeLocations, true, availabilityServiceContextV3); } private AvailabilityService createSupplierRequestTask(AvailabilityServiceContextV4 availabilityServiceContextV3, Part part, InventoryRelationshipsRequested relationshipsRequested, String correlationId, String clientId, String country, Set supplierLocations) { AvailabilityService supplierTask; if (relationshipsRequested.isAllSuppliers()) { supplierTask = new AvailabilityService(correlationId, clientId, country, "Supplier", part.getLineAbbrev(), part.getPartNumber(), ALL_SUPPLIERS, true, availabilityServiceContextV3); } else { supplierTask = new AvailabilityService(correlationId, clientId, country, "Supplier", part.getLineAbbrev(), part.getPartNumber(), supplierLocations, true, availabilityServiceContextV3); } return supplierTask; } private static AvailabilityService createDCRequestTask(AvailabilityServiceContextV4 availabilityServiceContextV3, Part part, InventoryRelationshipsRequested relationshipsRequested, String correlationId, String clientId, String country, Set dcLocations) { AvailabilityService dcTask; if (relationshipsRequested.isAllOtherDCs()) { dcTask = new AvailabilityService(correlationId, clientId, country, "DC", part.getLineAbbrev(), part.getPartNumber(), ALL_SUPPLIERS, true, availabilityServiceContextV3); } else {// we can send the individual DC requests dcTask = new AvailabilityService(correlationId, clientId, country, "DC", part.getLineAbbrev(), part.getPartNumber(), dcLocations, true, availabilityServiceContextV3); } return dcTask; } @Override public void setNonNapaInventoryFutures(AvailabilityServiceContextV4 availabilityServiceContextV3, Map siteIdToSiteMap) { SplunkLogger splunkLogger = new SplunkLogger(availabilityServiceContextV3.getRequest().getHeaderRequest()); LOGGER.debug(splunkLogger.toString() + " setNonNapaInventoryFutures "); //String cfgMgmtStores = configManagementService.getPilotStores(availabilityServiceContextV3); final List> posFutureList = new ArrayList<>(); //make a call for the calling store if pricing is requested or if supersedes are requeseted //applicable to calling store only and not calling DC or Supplier boolean canMakeStoreCall = false; // check if any related sites are need to make a TAMS call // if get from store flag is true, then we will need to make this call too for (RelatedSite relatedSite : availabilityServiceContextV3.getRelatedSites()) { //we need to figure out the posurl for each type of store //Need to get the storenumber String posURL = null; String posPassword = null; String storeNumber = null; boolean isCallingStore = false; if (availabilityServiceContextV3.getRequestingSite().getSiteIdentifier() == relatedSite.getSiteId()) { isCallingStore = true; } SiteDTO siteDTO = nSightCache.getSiteIdToSiteMap().get(relatedSite.getSiteId()); String requestingStore = availabilityServiceContextV3.getRequest().getHeaderRequest().getRequestor() .getRequestorIdentifier().getValue(); //make the call if getRetrieveFromStore flag is set or its the calling store and needpricing if (siteDTO.getRetrieveFromStore() || (siteDTO.getPosType() != null && siteDTO.getPosType().compareToIgnoreCase("NON_NAPA") == 0 && !nSightCache.getNonNapaStores().contains(requestingStore)) || (siteDTO.getPosType() != null && siteDTO.getPosType().compareToIgnoreCase("NON NAPA") == 0 && !nSightCache.getNonNapaStores().contains(requestingStore)) || (isCallingStore && availabilityServiceContextV3.getRequest().getActionRequest().getAction() .getNeedPricing()) || (isCallingStore && availabilityServiceContextV3.getRequest().getActionRequest().getAction() .getNeedSuperSedes())) { //Check if there are Other Sites and requestor application is FindItUAP to get the storenumber if (availabilityServiceContextV3.getRequest().getDetailRequest().getInventoryRelationshipsRequested() .getOtherSites() != null && availabilityServiceContextV3.getRequest().getHeaderRequest().getRequestor() .getRequestorApplication().compareToIgnoreCase("FinditUAP") == 0) { String otherSiteStoreNumber = availabilityServiceContextV3.getOtherSitesStoreNumber() .get(relatedSite.getSiteId()); if (otherSiteStoreNumber != null) { storeNumber = otherSiteStoreNumber; } }//get the store number from the request only for calling store else if (isCallingStore && availabilityServiceContextV3.getRequest().getHeaderRequest().getRequestor().getRequestorIdentifier() .getType().compareToIgnoreCase("9 Digit Store Number") == 0) { storeNumber = availabilityServiceContextV3.getRequest().getHeaderRequest().getRequestor() .getRequestorIdentifier().getValue(); } if (storeNumber == null || storeNumber.length() == 0) { for (SiteIdentifier siteIdentifier : siteDTO.getSiteIdentifierList()) { if (siteIdentifier.getName().compareToIgnoreCase("9 Digit Store Number") == 0) { storeNumber = siteIdentifier.getValue(); break; } } } //since we have two URLS for RPM,we need to check which one to use boolean useRPMV2 = false; if (siteDTO != null && siteDTO.getPosType() != null && siteDTO.getPosType().compareToIgnoreCase("RPM") == 0) { useRPMV2 = isUsingRPMV2(siteDTO, availabilityServiceContextV3); if (useRPMV2) { posURL = nSightProperties.getRpmURLV2(); } else { posURL = nSightProperties.getRpmURL(); } } else { posURL = constructPOSUrl(siteDTO, storeNumber, availabilityServiceContextV3); } try { if (isCallingStore) {//use the password from the request //skip for calling store if its FindITUAP since findit is not interested in inventory for the calling store if (availabilityServiceContextV3.getRequest().getHeaderRequest().getRequestor() .getRequestorApplication().compareToIgnoreCase("FinditUAP") == 0) { String otherSitePassword = availabilityServiceContextV3.getOtherSitesPassword() .get(relatedSite.getSiteId()); if (otherSitePassword != null) { posPassword = otherSitePassword; } else { posPassword = relatedSite.getPosPassword(); } } else { if (availabilityServiceContextV3.getRequest().getHeaderRequest().getResponder() .getSecurity() != null && availabilityServiceContextV3.getRequest().getHeaderRequest().getResponder() .getSecurity().getUserCredentials() != null && availabilityServiceContextV3.getRequest().getHeaderRequest().getResponder() .getSecurity().getUserCredentials().getPassword() != null) { posPassword = availabilityServiceContextV3.getRequest().getHeaderRequest() .getResponder().getSecurity().getUserCredentials().getPassword(); } else { posPassword = relatedSite.getPosPassword(); } } } else { //use password if its passed in via othersites if (availabilityServiceContextV3.getRequest().getDetailRequest() .getInventoryRelationshipsRequested().getOtherSites() != null) { String otherSitePassword = availabilityServiceContextV3.getOtherSitesPassword() .get(relatedSite.getSiteId()); if (otherSitePassword != null) { posPassword = otherSitePassword; } else { posPassword = relatedSite.getPosPassword(); } } else { posPassword = relatedSite.getPosPassword(); } } } catch (Exception ex) { LOGGER.info(splunkLogger.toString() + " Exception in POS password {} ", ex.getStackTrace()); } if (posPassword != null && posURL != null && relatedSite.getSiteId() != null && relatedSite.getPosType() != null) { if (storeNumber != null) { availabilityServiceContextV3.getFromSiteIds().add(relatedSite.getSiteId()); //lets add this to the list of inventories found when we make the request since we //cant wait for the response due to latency. This list is used to retrieve delivery upfront if (relatedSite.getSiteId() != availabilityServiceContextV3.getRequestingSite() .getSiteIdentifier()) { availabilityServiceContextV3.getSitesWithInventory().add(relatedSite.getSiteId()); } //create a part set that also includes virtual kits too Set partSet = new HashSet<>(); partSet.addAll(availabilityServiceContextV3.getPartSet()); if (availabilityServiceContextV3.getParentPartMap() != null && availabilityServiceContextV3.getParentPartMap().size() > 0) { for (Map.Entry entry : availabilityServiceContextV3.getParentPartMap() .entrySet()) { partSet.add(entry.getValue()); } } if (siteDTO.getPosType().compareToIgnoreCase("RPM") == 0) { ListenableFuture ListenableFuture = posServiceExecutor.submit( new POSService(partSet, relatedSite.getPosType(), posURL, posPassword, relatedSite.getSiteId(), storeNumber, rpmContext, nSightProperties.getRpmTimeout(), availabilityServiceContextV3.getRequest().getHeaderRequest(), availabilityServiceContextV3.getRpmSecurity(), null, null, useRPMV2, nSightProperties.getRpmUser(), nSightProperties.getRpmPassword())); posFutureList.add(ListenableFuture); } else { int storeTimeout = nSightProperties.getTamsTimeout(); if (availabilityServiceContextV3.getRequest().getHeaderRequest().getRequestor() .getRequestorApplication().compareToIgnoreCase("ISSCQuery") == 0) { storeTimeout = nSightProperties.getIsscTimeout(); } ListenableFuture ListenableFuture = posServiceExecutor.submit( new POSService(partSet, relatedSite.getPosType(), posURL, posPassword, relatedSite.getSiteId(), storeNumber, context, storeTimeout, availabilityServiceContextV3.getRequest().getHeaderRequest(), availabilityServiceContextV3.getRpmSecurity(), null, null, useRPMV2, nSightProperties.getRpmUser(), nSightProperties.getRpmPassword())); posFutureList.add(ListenableFuture); } canMakeStoreCall = true; } } else { //if (availabilityServiceContextV2.getRequest().getHeaderRequest().getRequestor().getRequestorApplication().compareToIgnoreCase("FinditUAP")!=0) // canMakeStoreCall = false; LOGGER.info(splunkLogger.toString() + " POSURL or POS password Not Present {} ", relatedSite.getSiteId()); } }//need to make calls to stores } //if we didnt have all the info to make a call to storee if (canMakeStoreCall) { availabilityServiceContextV3.setNonNapaInventoryFutures(Futures.inCompletionOrder(posFutureList)); } else { for (ListenableFuture listenableFuture : posFutureList) { if (listenableFuture != null) { listenableFuture.cancel(true); } } posFutureList.clear(); availabilityServiceContextV3.setCallNonTAMS(false); } } @Override public void setInventoryFutures(AvailabilityServiceContextV4 availabilityServiceContextV3) { SplunkLogger splunkLogger = new SplunkLogger(availabilityServiceContextV3.getRequest().getHeaderRequest()); LOGGER.debug(splunkLogger.toString() + " setInventoryFutures "); DetailRequest detailRequest = availabilityServiceContextV3.getRequest().getDetailRequest(); final List resultSetFutureList = new ArrayList<>(); Map resultSetFutureUapDcInvCdMap = new HashMap(); long startTime = System.currentTimeMillis(); //Go through the list of relationships that are requested and create the Inventory calls //Make the DC inventory calls if (detailRequest.getInventoryRelationshipsRequested().isAllOtherDCs()) { availabilityServiceContextV3.getPartSet().stream().map((part) -> { return getInventory(availabilityServiceContextV3, availabilityServiceContextV3.isAggregate() ? "AllOtherDCs_Aggregate" : "AllOtherDCs", part.getPartNumber(), part.getLineAbbrev(), null, null, null); } ).forEach(resultSetFutureList::add); } else if (detailRequest.getInventoryRelationshipsRequested().isServingDC() && !detailRequest.getInventoryRelationshipsRequested().isAllOtherDCs() && availabilityServiceContextV3.getPrimaryDC() != null) { availabilityServiceContextV3.getPartSet().stream().map((part) -> { return getInventory(availabilityServiceContextV3, availabilityServiceContextV3.isAggregate() ? "PrimaryDC_Aggregate" : "PrimaryDC", part.getPartNumber(), part.getLineAbbrev(), null, availabilityServiceContextV3.getPrimaryDC().getSiteId(), null); } ).forEach(resultSetFutureList::add); } //Make the UAP DC inventory code calls for UAP stores if (detailRequest.getInventoryRelationshipsRequested().isServingDC() && !detailRequest.getInventoryRelationshipsRequested().isAllOtherDCs() && availabilityServiceContextV3.getPrimaryDC() != null && availabilityServiceContextV3.getRequestingSite().getStorePartitionKey() != null && availabilityServiceContextV3.getRequestingSite().getStorePartitionKey().contains("CAN") && availabilityServiceContextV3.getB2bSDK() != null && availabilityServiceContextV3.getB2bSDK() .equalsIgnoreCase("nol-ca")) { availabilityServiceContextV3.getPartSet().stream().forEach(part -> { String key = null; ResultSetFuture resultsetFuture = null; key = part.getPartNumber() + part.getLineAbbrev() + availabilityServiceContextV3.getPrimaryDC() .getSiteId(); resultsetFuture = getInventory(availabilityServiceContextV3, "PrimaryUAPDCInventoryCode", part.getPartNumber(), part.getLineAbbrev(), null, availabilityServiceContextV3.getPrimaryDC().getSiteId(), null); resultSetFutureUapDcInvCdMap.put(key, resultsetFuture); } ); availabilityServiceContextV3.setInventoryFutureUapDcInvCdMap(resultSetFutureUapDcInvCdMap); } //make the Supplier inventory calls if (detailRequest.getInventoryRelationshipsRequested().isAllSuppliers()) { availabilityServiceContextV3.getPartSet().stream().map((part) -> { return getInventory(availabilityServiceContextV3, availabilityServiceContextV3.isAggregate() ? "Supplier_Aggregate" : "Supplier", part.getPartNumber(), part.getLineAbbrev(), null, null, null); } ).forEach(resultSetFutureList::add); } //Now go through the list of related sites that were requested based on relationships or other sites //Use the appropriate Prepared Statement depending on the type or whether its a detail or aggregate //availabilityServiceContext.getRelatedSites().stream().filter(relatedSite -> relatedSite.getPartKey() != null).forEach(relatedSite -> { // These would be DC/Supplier/Store inventory calls availabilityServiceContextV3.getRelatedSites().stream().filter(relatedSite -> relatedSite.getSiteId() != null) .forEach(relatedSite -> { availabilityServiceContextV3.getFromSiteIds().add(relatedSite.getSiteId()); availabilityServiceContextV3.getPartSet().stream().map((part) -> { //Since the related sites could by a DC,Supplier or Store, we need to determine the type if (relatedSite.getType().equals("DC") && !detailRequest.getInventoryRelationshipsRequested() .isAllOtherDCs()) { return getInventory(availabilityServiceContextV3, availabilityServiceContextV3.isAggregate() ? "AnyDC_Aggregate" : "AnyDC", part.getPartNumber(), part.getLineAbbrev(), relatedSite.getPartKey(), relatedSite.getSiteId(), null); } else if (relatedSite.getType().equals("Supplier") && !detailRequest.getInventoryRelationshipsRequested().isAllSuppliers()) { return getInventory(availabilityServiceContextV3, availabilityServiceContextV3.isAggregate() ? "AnySupplier_Aggregate" : "AnySupplier", part.getPartNumber(), part.getLineAbbrev(), relatedSite.getPartKey(), relatedSite.getSiteId(), null); } else {//its a store SiteDTO siteDTORelated = nSightCache.getSiteIdToSiteMap().get(relatedSite.getSiteId()); //make a nisght inventory call only if getfromstore flag is false if (part.getPartNumber() != null && part.getLineAbbrev() != null && relatedSite.getPartKey() != null && relatedSite.getSiteId() != null && !siteDTORelated.getRetrieveFromStore()) { //if pricing is set to true and its the calling store then we dont need to make a call to nsight for availability //not sure why this condition is there. we should make both the calls and then merge the reuslts. going to comment it for now /* Commenting below condition caused issue for ISSC query request. When both calls are made, inventory part taking precedence over non inventory part. Due to this part attributes(group code, class year) from store are dropped. TAMS showed incorrect pricing as those attributes missing in ISSC query response */ /* added so that we can merge rest of the fields from nsight with pos results if (availabilityServiceContextV3.getRequest().getActionRequest().getAction().getNeedPricing() && relatedSite.getSiteId()== availabilityServiceContextV3.getRequestingSite().getSiteIdentifier()) return null; else*/ return getInventory(availabilityServiceContextV3, availabilityServiceContextV3.isAggregate() ? "Store_Aggregate" : "Store", part.getPartNumber(), part.getLineAbbrev(), relatedSite.getPartKey(), relatedSite.getSiteId(), relatedSite.getPosType()); } else { return null; } } } ).forEach(resultSetFutureList::add); }); //remove any Futures that could be null resultSetFutureList.removeIf(Objects::isNull); LOGGER.debug(splunkLogger.toString() + " Total Inventory queries in {}", resultSetFutureList.size()); availabilityServiceContextV3.setInventoryFutures(Futures.inCompletionOrder(resultSetFutureList)); } @Override public void processNonNapaInventoryFutures(AvailabilityServiceContextV4 availabilityServiceContextV3) { SplunkLogger splunkLogger = new SplunkLogger(availabilityServiceContextV3.getRequest().getHeaderRequest()); if (availabilityServiceContextV3.getNonNapaInventoryFutures() != null) { //Loop through all the futures. each future is a response for a single store with multiple parts Map> inventoryMap = availabilityServiceContextV3.getNonNapaInventoryFutures() .stream().flatMap(posServiceResponseListenableFuture -> { List parts = new ArrayList<>(); POSServiceResponse posServiceResponse = null; try { posServiceResponse = posServiceResponseListenableFuture.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } //valid future response if (posServiceResponse != null && posServiceResponse.getPosServiceResponseData() != null && posServiceResponse.getPosServiceResponseData().size() > 0) { String siteIdentifier = posServiceResponse.getSiteId(); //loop through all the parts for that store for (POSServiceResponseData posServiceResponseData : posServiceResponse.getPosServiceResponseData()) { try { String lineAbbrev = posServiceResponseData.getLineAbbrev(); String msg = posServiceResponseData.getMessage(); if (msg != null && !msg.contains("Part Not Found")) { SiteDTO currentStore = nSightCache.getSiteIdToSiteMap().get(siteIdentifier); //apply hqline abbrev logic Set inHqLineAbbrevList = nSightCache.getSupplierHQMap() .get(lineAbbrev);//get them from suppiler instead of the callling store if (currentStore != null) { List currentStoreHqLineAbbrev = currentStore.getHqLineAbbrevMapping() .get(lineAbbrev); if ((currentStoreHqLineAbbrev == null) || availabilityServiceContextV3.isSkipHQLineAbbrev() || ( inHqLineAbbrevList != null && currentStoreHqLineAbbrev != null && !Collections.disjoint(currentStoreHqLineAbbrev, inHqLineAbbrevList))) { com.genpt.nsight.v4.model.Part part = new com.genpt.nsight.v4.model.Part(); String partNumber = posServiceResponseData.getPartNumber(); part.setPartNumber(partNumber); part.setLineAbbrev(lineAbbrev); if (!(msg.contains("Renumbered as") || msg.contains("Reorder as") || msg.contains("Can use") || msg.contains("Superseded by"))) { part.setMessage(msg); } com.genpt.nsight.v4.model.Site site = new com.genpt.nsight.v4.model.Site(); part.setSite(site); site.setSiteType(currentStore.getSiteType()); site.setSiteId(siteIdentifier); //populate rawDelivery times from Store only for B2B clients if (nSightProperties.getB2bServices().contains( availabilityServiceContextV3.getRequest().getHeaderRequest() .getRequestor().getRequestorApplication())) { if (posServiceResponseData.getDeliveryTime() != null) { site.setDeliveryTime(posServiceResponseData.getDeliveryTime()); } if (currentStore.getStoreAlias() != null) { site.setStoreAlias(currentStore.getStoreAlias()); } } if (availabilityServiceContextV3.getRequest().getActionRequest().getAction() .getNeedPricing()) { //pricing for only calling store only if requested if (siteIdentifier.compareToIgnoreCase( availabilityServiceContextV3.getRequestingSite() .getSiteIdentifier()) == 0) { HashMap priceTypes = new HashMap(); PriceType priceType = new PriceType(); for (POSPrice posPrice : posServiceResponseData.getPosPrices()) { if (posPrice.getPriceType().compareToIgnoreCase("PRI") == 0) { priceType.setListPrice(posPrice.getListPrice()); priceType.setCustomerPrice(posPrice.getYourCost()); } if (posPrice.getPriceType().compareToIgnoreCase("COR") == 0) { priceType.setCoreListPrice(posPrice.getListPrice()); priceType.setCoreCustomerPrice(posPrice.getYourCost()); } if (posPrice.getPriceType().compareToIgnoreCase("COR") != 0 && posPrice.getPriceType().compareToIgnoreCase("PRI") != 0) { //this is a miscellaneous charge if (priceType.getMiscCharges() == null) { priceType.setMiscCharges(new ArrayList<>()); } MiscCharge miscCharge = new MiscCharge(); miscCharge.setMiscType(posPrice.getPriceType()); miscCharge.setMiscListPrice(posPrice.getListPrice()); //add a null check for below especially for ISSC if (posPrice.getYourCost() != null) { miscCharge.setMiscCustomerPrice(posPrice.getYourCost()); } priceType.getMiscCharges().add(miscCharge); } } Tracking tracking = new Tracking(); tracking.setIsSuccess(true); priceType.setTracking(tracking); part.setPrice(priceType); }//end of pricing } //Need Supersedes if (availabilityServiceContextV3.getRequest().getActionRequest().getAction() .getNeedSuperSedes()) { if (msg != null) { if (msg.contains("Renumbered as") || msg.contains("Reorder as") || msg.contains("Can use") || msg.contains("Superseded by")) { List supersedesList = new ArrayList(); msg = msg.replaceAll(" ", " "); String[] msgParts = msg.split(" "); if (msgParts.length == 4 || msgParts.length == 7) { if (msg.contains("Renumbered as")) { supersedesList = setSupersedes(msg, SuperSedeseTypes.RENUMBERED.name()); } if (msg.contains("Reorder as")) { supersedesList = setSupersedes(msg, SuperSedeseTypes.REORDER.name()); } if (msg.contains("Can use")) { supersedesList = setSupersedes(msg, SuperSedeseTypes.SUBSTITUTE.name()); } if (msg.contains("Superseded by")) { supersedesList = setSupersedes(msg, SuperSedeseTypes.SUPERSEDED_BY.name()); } } else { supersedesList = setSupersedes(msg, SuperSedeseTypes.MISC.name()); } //add the supersede to the response if (supersedesList != null) { site.setSuperSedes(supersedesList); } } } }//end of supersedes availabilityServiceContextV3.getSiteWithPartsAvailable() .add(siteIdentifier); BigDecimal availableQuantity = BigDecimal.valueOf( posServiceResponseData.getQuantityOnHand()); if (!availabilityServiceContextV3.isAggregate()) { if (nSightCache.getSiteIdToSiteMap().get(siteIdentifier) != null) { site.setSiteIdentifiers( nSightCache.getSiteIdToSiteMap().get(siteIdentifier) .getSiteIdentifierList()); } long date = System.currentTimeMillis() / 1000; site.setSourceSystemDataAsOfDate(date); site.setTracking(tracking); Quantity quantity = new Quantity(); if (availableQuantity != null) { quantity.setOnHand(availableQuantity); } if (availableQuantity != null) { quantity.setAvailable(availableQuantity); } BigDecimal workInProgress = null; //only for ISSC query if (availabilityServiceContextV3.getRequest().getHeaderRequest() .getRequestor().getRequestorApplication() .compareToIgnoreCase("ISSCQuery") == 0) { workInProgress = BigDecimal.valueOf( posServiceResponseData.getWorkInProgress()); quantity.setWorkInProgress(workInProgress); } site.setQuantity(quantity); PartAttributes partAttributes = new PartAttributes(); partAttributes.setPartDescription( posServiceResponseData.getDescription()); partAttributes.setUnitOfMeasure("EA"); //only for ISSC queries if (availabilityServiceContextV3.getRequest().getHeaderRequest() .getRequestor().getRequestorApplication() .compareToIgnoreCase("ISSCQuery") == 0) { if (posServiceResponseData.getCurrentClass() != null) { partAttributes.setCurrentClass( posServiceResponseData.getCurrentClass()); } if (posServiceResponseData.getGroupCode() != null) { partAttributes.setGroupCode( posServiceResponseData.getGroupCode()); } //supersedes for ISSC if (posServiceResponseData.getSupersedeType() != null) { SuperSede superSede = new SuperSede(); List superSedeList = new ArrayList(); superSede.setSuperSedeType( posServiceResponseData.getSupersedeType()); superSede.setLineAbbrev( posServiceResponseData.getSupersedeLineAbbrev1()); superSede.setPartNumber( posServiceResponseData.getSupersedePartNumber1()); superSedeList.add(superSede); site.setSuperSedes(superSedeList); } }//ISSC request site.setPartAttributes(partAttributes); }//not aggregate if (availableQuantity != null) { site.setAvailableQuantity( availableQuantity.intValue()); //Can use this for calculations } parts.add(part); }//valid HQlineAbbrev }//Valid CurrentStore } } catch (Exception e) { //e.printStackTrace(); LOGGER.error(splunkLogger.toString() + " Error while processing NonNAPA Futures, Message : {}, StackTrace: {} ", e.getMessage(), e.getStackTrace()); } }//end of iterate parts on have a succese response from the stores } else {//failure response from store String siteIdentifier = posServiceResponse.getSiteId(); //populate this only if itss the calling sstore //for other store or DC endpoints, skip this SiteDTO siteDTO = nSightCache.getSiteIdToSiteMap().get(siteIdentifier); if (siteDTO.getSiteIdentifier() .compareToIgnoreCase(availabilityServiceContextV3.getRequestingSite().getSiteIdentifier()) == 0) { for (String partKey : availabilityServiceContextV3.getInputParts().keySet()) { com.genpt.nsight.v4.model.Part inputPartKey = availabilityServiceContextV3.getInputParts() .get(partKey); com.genpt.nsight.v4.model.Part inputPart = new com.genpt.nsight.v4.model.Part(); inputPart.setLineAbbrev(inputPartKey.getLineAbbrev()); inputPart.setPartNumber(inputPartKey.getPartNumber()); com.genpt.nsight.v4.model.Site site = new com.genpt.nsight.v4.model.Site(); inputPart.setSite(site); site.setSiteType(siteDTO.getSiteType()); site.setSiteId(siteDTO.getSiteIdentifier()); if (nSightProperties.getB2bServices().contains( availabilityServiceContextV3.getRequest().getHeaderRequest().getRequestor() .getRequestorApplication())) { if (siteDTO.getStoreAlias() != null) { site.setStoreAlias(siteDTO.getStoreAlias()); } } Tracking tracking = new Tracking(); tracking.setIsSuccess(false); tracking.setLog(Collections.singletonList( new Log("2001", "Unable to Retrieve Availability From " + siteDTO.getPosType()))); tracking.setFault(Fault.builder().code(posServiceResponse.getStatusCode()) .message(posServiceResponse.getStatusMessage()).build()); site.setTracking(tracking); if (!availabilityServiceContextV3.isAggregate()) { if (nSightCache.getSiteIdToSiteMap().get(siteIdentifier) != null) { site.setSiteIdentifiers(nSightCache.getSiteIdToSiteMap().get(siteIdentifier) .getSiteIdentifierList()); } long date = System.currentTimeMillis() / 1000; site.setSourceSystemDataAsOfDate(date); }//not aggregate //calling store. so for all parts set the tracking with the error if (availabilityServiceContextV3.getRequest().getActionRequest().getAction() .getNeedPricing()) { if (siteDTO != null && siteDTO.getSiteIdentifier().compareToIgnoreCase(posServiceResponse.getSiteId()) == 0) { if (posServiceResponse.getStatusCode() != null && posServiceResponse.getStatusMessage() != null) { availabilityServiceContextV3.setPricingStatusCode( posServiceResponse.getStatusCode()); availabilityServiceContextV3.setPricingStatusMessage( posServiceResponse.getStatusMessage()); } } } inputPart.setTracking(tracking); parts.add(inputPart); }//end of for each part } } return parts.stream(); }).collect(Collectors.groupingBy(p -> p.getPartNumber() + "-" + p.getLineAbbrev())); availabilityServiceContextV3.setNonNapaInventory(inventoryMap); }//valid futures } @Override public Map> processAvailabilityAsyncResponses(AvailabilityServiceContextV4 availabilityServiceContextV4){ SplunkLogger splunkLogger = new SplunkLogger(availabilityServiceContextV4.getRequest().getHeaderRequest()); Stopwatch sw = Stopwatch.createStarted(); Map> inventoryMap = null; if(availabilityServiceContextV4.getGcpInventoryFutures() !=null) { inventoryMap = asyncAvailabilityClient.processAllResponses(availabilityServiceContextV4.getGcpInventoryFutures()).stream().flatMap(inventoryResponseV1 -> { List parts = new ArrayList<>(); processInventoryResponsesFromBT(inventoryResponseV1, splunkLogger, availabilityServiceContextV4, parts); return parts.stream(); }).collect(Collectors.groupingBy(p -> p.getPartNumber() + "-" + p.getLineAbbrev())); } LOGGER.info(splunkLogger.toString()+" Finished processing All Availability Async responses in {}", sw.stop()); return inventoryMap; } @Override public Map> processMultiProductAsyncResponses(AvailabilityServiceContextV4 availabilityServiceContextV4){ SplunkLogger splunkLogger = new SplunkLogger(availabilityServiceContextV4.getRequest().getHeaderRequest()); Stopwatch sw = Stopwatch.createStarted(); Map> inventoryMap = null; if(availabilityServiceContextV4.getGcpMultiProductInventoryFutures() !=null ) { inventoryMap = asyncAvailabilityClient.processMultiproductResponse(availabilityServiceContextV4.getGcpMultiProductInventoryFutures()).getParts().stream().flatMap(inventoryResponseV1 -> { List parts = new ArrayList<>(); processInventoryResponsesFromBT(inventoryResponseV1, splunkLogger, availabilityServiceContextV4, parts); return parts.stream(); }).collect(Collectors.groupingBy(p -> p.getPartNumber() + "-" + p.getLineAbbrev())); } LOGGER.info(splunkLogger.toString()+" Finished processing All MultiProduct Async responses in {} ", sw.stop()); return inventoryMap; } private void processInventoryResponsesFromBT(InventoryResponseV1 inventoryResponseV1, SplunkLogger splunkLogger, AvailabilityServiceContextV4 availabilityServiceContextV4,List parts){ InventoryResponseV1 finalInventoryResponseV = inventoryResponseV1; inventoryResponseV1.getQuantities() .forEach(quantityDetailsV1 -> {//for each location for that part String siteIdentifier = nSightCache.getAliasToSiteIdMap().get( quantityDetailsV1.getLocationIdentifier().getName() + "|" + quantityDetailsV1.getLocationIdentifier().getValue()); LOGGER.debug(splunkLogger.toString() + " found site {} with part {} {} ", siteIdentifier, finalInventoryResponseV.getProductCd(), finalInventoryResponseV.getProductNbr()); if (quantityDetailsV1.getAvailQty() == null && quantityDetailsV1.getOnHandQty() == null) {//check if both values LOGGER.warn(splunkLogger.toString() + " Available and OnHand Quantity is null for site : {} Product Cd {} Product Nbr {}", siteIdentifier, finalInventoryResponseV.getProductCd(), finalInventoryResponseV.getProductNbr()); return; } SiteDTO currentLocation = nSightCache.getSiteIdToSiteMap().get(siteIdentifier); if (siteIdentifier != null && currentLocation != null) {// site id could be null if the site is inactive, remove it? //let's populate a Set of sites where we have found Inventory availabilityServiceContextV4.getSitesWithInventory().add(siteIdentifier); Part part = new Part(); part.setPartNumber(finalInventoryResponseV.getProductNbr()); part.setLineAbbrev(finalInventoryResponseV.getProductCd()); com.genpt.nsight.v4.model.Site site = new com.genpt.nsight.v4.model.Site(); part.setSite(site); site.setSiteType(quantityDetailsV1.getLocationIdentifier().getType()); //need to set the site identifier too site.setSiteId(siteIdentifier); //for now only for B2B clients if (nSightProperties.getB2bServices().contains( availabilityServiceContextV4.getRequest().getHeaderRequest().getRequestor() .getRequestorApplication())) { if (currentLocation.getStoreAlias() != null) { site.setStoreAlias(currentLocation.getStoreAlias()); } } availabilityServiceContextV4.getSiteWithPartsAvailable().add(siteIdentifier); BigDecimal availableQuantity = null; if (quantityDetailsV1.getAvailQty() != null) { availableQuantity = quantityDetailsV1.getAvailQty(); } if (!availabilityServiceContextV4.isAggregate()) {//not the aggregate service if (nSightCache.getSiteIdToSiteMap().get(siteIdentifier) != null) { site.setSiteIdentifiers(nSightCache.getSiteIdToSiteMap().get(siteIdentifier) .getSiteIdentifierList()); } if (quantityDetailsV1.getDataAsOfTS() != 0) { site.setSourceSystemDataAsOfDate(quantityDetailsV1.getDataAsOfTS()); } site.setTracking(tracking); Quantity quantity = new Quantity(); if (quantityDetailsV1.getOnHandQty() != null) { quantity.setOnHand(quantityDetailsV1.getOnHandQty()); } if (quantityDetailsV1.getAvailQty() != null) { quantity.setAvailable(quantityDetailsV1.getAvailQty()); } else { quantity.setAvailable(quantity.getOnHand()); } if (quantityDetailsV1.getOnOrdQty() != null) { quantity.setOnOrder(quantityDetailsV1.getOnOrdQty().intValue()); } quantity.setMinimumSellQuantity(quantityDetailsV1.getMinSellQty()); quantity.setMinStockedQuantity(quantityDetailsV1.getMinStockQty()); quantity.setMaxStockedQuantity(quantityDetailsV1.getMaxStockQty()); quantity.setIncrementalSellQuantity(quantityDetailsV1.getIncrSellQty()); /* if ("Supplier".equals(quantityDetailsV1.getLocationIdentifier().getType())) { quantity.setOrderSinceLastUpdate(quantityDetailsV1.or); }*/ if (quantityDetailsV1.getOnOrdDt() != null) { quantity.setOnOrderDate(quantityDetailsV1.getOnOrdDt()); } quantity.setInTransit(quantityDetailsV1.getInTransQty()); if (quantityDetailsV1.getInTransDt() != null) { quantity.setInTransitDate(quantityDetailsV1.getInTransDt()); } site.setQuantity(quantity); PartAttributes partAttributes = new PartAttributes(); if (quantityDetailsV1.getProductAttributes() != null) { partAttributes.setPartDescription( quantityDetailsV1.getProductAttributes().getDesc()); partAttributes.setUnitOfMeasure( quantityDetailsV1.getProductAttributes().getUom()); } site.setPartAttributes(partAttributes); //needed only in details and not aggregate } else {// aggregate } if (availableQuantity != null) { site.setAvailableQuantity( availableQuantity.intValue()); //Can use this for calculations } parts.add(part); }//end of valid location });// iterate sites for that part } @Override public Map> processInventoryFutures(AvailabilityServiceContextV4 availabilityServiceContextV3) { SplunkLogger splunkLogger = new SplunkLogger(availabilityServiceContextV3.getRequest().getHeaderRequest()); //reset the list where inventory is found availabilityServiceContextV3.getSitesWithInventory().clear(); Map> inventoryMap = availabilityServiceContextV3.getInventoryFutures() .stream().flatMap(resultSetListenableFuture -> { ResultSet resultSet = null; List parts = new ArrayList<>(); try { resultSet = resultSetListenableFuture.get(); while (!resultSet.isExhausted()) { Row row = resultSet.one(); String siteIdentifier = row.getUUID("site_identifier").toString(); String lineAbbrev = row.getString("line_abbrev"); String partNumber = row.getString("part_number"); if (row.getDecimal("available_quantity") == null && row.getDecimal("on_hand_quantity") == null) {//check if both values LOGGER.warn(splunkLogger.toString() + " Available and OnHand Quantity is null for site : {} Part {} LineAbbrev {}", siteIdentifier, lineAbbrev, partNumber); continue; } //lets populate a Set of sites where we have found Inventory availabilityServiceContextV3.getSitesWithInventory().add(siteIdentifier); //this is a check if we need to execute the HQ Abbrev logic //get the hqabbrev for the calling store for this lineabbrev //List inHqLineAbbrevList = availabilityServiceContextV3.getRequestingSite().getHqLineAbbrevMapping().get(lineAbbrev); Set inHqLineAbbrevList = nSightCache.getSupplierHQMap() .get(lineAbbrev);//get them from suppiler instead of the callling store //if we dont find a entry in the supplier map all sites would be dropped //if (!availabilityServiceContextV3.isSkipHQLineAbbrev() || inHqLineAbbrevList != null) { SiteDTO currentStore = nSightCache.getSiteIdToSiteMap().get(siteIdentifier); if (currentStore != null) { //check if the hq abbrev matches for this site matches the hqabbrev of the calling site List currentStoreHqLineAbbrev = currentStore.getHqLineAbbrevMapping() .get(lineAbbrev); if ((currentStoreHqLineAbbrev == null) || availabilityServiceContextV3.isSkipHQLineAbbrev() || (inHqLineAbbrevList != null && currentStoreHqLineAbbrev != null && !Collections.disjoint( currentStoreHqLineAbbrev, inHqLineAbbrevList))) { com.genpt.nsight.v4.model.Part part = new com.genpt.nsight.v4.model.Part(); partNumber = row.getString("part_number"); part.setPartNumber(partNumber); part.setLineAbbrev(lineAbbrev); com.genpt.nsight.v4.model.Site site = new com.genpt.nsight.v4.model.Site(); part.setSite(site); site.setSiteType(currentStore.getSiteType()); site.setSiteId(siteIdentifier); //for now only for B2B clients if (nSightProperties.getB2bServices().contains( availabilityServiceContextV3.getRequest().getHeaderRequest().getRequestor() .getRequestorApplication())) { if (currentStore.getStoreAlias() != null) { site.setStoreAlias(currentStore.getStoreAlias()); } } availabilityServiceContextV3.getSiteWithPartsAvailable().add(siteIdentifier); BigDecimal availableQuantity = null; if (row.getDecimal("available_quantity") != null) { availableQuantity = row.getDecimal("available_quantity"); } if (availabilityServiceContextV3.getInventoryFutureUapDcInvCdMap() != null && availabilityServiceContextV3.getInventoryFutureUapDcInvCdMap().size() > 0 && availabilityServiceContextV3.getInventoryFutureUapDcInvCdMap() != null && availabilityServiceContextV3.getInventoryFutureUapDcInvCdMap() .get(partNumber + lineAbbrev + siteIdentifier) != null) { ResultSet resultSetUapDcInvCd = availabilityServiceContextV3.getInventoryFutureUapDcInvCdMap() .get(partNumber + lineAbbrev + siteIdentifier).get(); if (resultSetUapDcInvCd != null) { Row rowUapDcInvCd = resultSetUapDcInvCd.one(); if (rowUapDcInvCd != null && rowUapDcInvCd.getDecimal("inventory_code") != null && availableQuantity != null) { BigDecimal inventoryCode = rowUapDcInvCd.getDecimal("inventory_code"); availableQuantity = availableQuantity.add(inventoryCode); } else if (rowUapDcInvCd != null && rowUapDcInvCd.getDecimal("inventory_code") != null) { availableQuantity = rowUapDcInvCd.getDecimal("inventory_code"); } } } if (!availabilityServiceContextV3.isAggregate()) { if (nSightCache.getSiteIdToSiteMap().get(siteIdentifier) != null) { site.setSiteIdentifiers(nSightCache.getSiteIdToSiteMap().get(siteIdentifier) .getSiteIdentifierList()); } long date = 0; if (row.getTimestamp("data_as_of_ts") != null) { date = row.getTimestamp("data_as_of_ts").getTime(); if (date != 631152000000L) { site.setSourceSystemDataAsOfDate(date / 1000); } } site.setTracking(tracking); Quantity quantity = new Quantity(); if (row.getDecimal("on_hand_quantity") != null) { quantity.setOnHand(row.getDecimal("on_hand_quantity")); } if (availableQuantity != null) { quantity.setAvailable(availableQuantity); } else { quantity.setAvailable(quantity.getOnHand()); } quantity.setOnOrder(row.getInt("on_order_quantity")); quantity.setMinimumSellQuantity(row.getInt("min_sell_quantity")); quantity.setMinStockedQuantity(row.getInt("min_stock_quantity")); quantity.setMaxStockedQuantity(row.getInt("max_stock_quantity")); quantity.setIncrementalSellQuantity(row.getInt("increment_sell_quantity")); if ("Supplier".equals(currentStore.getSiteType())) { quantity.setOrderSinceLastUpdate( row.getInt("order_since_last_update_quantity")); } if (row.getTimestamp("on_order_ts") != null) { date = row.getTimestamp("on_order_ts").getTime(); if (date != 631152000000L) { quantity.setOnOrderDate(date / 1000); } } quantity.setInTransit(row.getInt("in_transit_quantity")); if (row.getTimestamp("in_transit_ts") != null) { date = row.getTimestamp("in_transit_ts").getTime(); if (date != 631152000000L) { quantity.setInTransitDate(date / 1000); } } site.setQuantity(quantity); PartAttributes partAttributes = new PartAttributes(); if (row.getString("part_description") != null) { partAttributes.setPartDescription(row.getString("part_description")); } if (row.getString("unit_of_measure_designator") != null) { partAttributes.setUnitOfMeasure( row.getString("unit_of_measure_designator")); } site.setPartAttributes(partAttributes); } else { if ("Supplier".equals(site.getSiteType())) { int orderSinceLastUpdate = row.getInt("order_since_last_update_quantity"); if (orderSinceLastUpdate != Integer.MIN_VALUE) { site.setOrderSinceLastUpdate(orderSinceLastUpdate); } } } if (availableQuantity != null) { site.setAvailableQuantity( availableQuantity.intValue()); //Can use this for calculations } parts.add(part); } } } }//end of while of iterating resultset from Cassandra } catch (Exception e) { //e.printStackTrace(); LOGGER.error(splunkLogger.toString() + " Error while processing Cassandra Futures, ApplicationID: {}, CorrelationID : {}, Message : {}, StackTrace: {} ", availabilityServiceContextV3.getApplicationID(), availabilityServiceContextV3.getCorrelationID(), e.getMessage(), e.getStackTrace()); } return parts.stream(); }).collect(Collectors.groupingBy(p -> p.getPartNumber() + "-" + p.getLineAbbrev())); availabilityServiceContextV3.setInventory(inventoryMap); return inventoryMap; } private String constructPOSUrl(SiteDTO siteDTO, String storeNumber, AvailabilityServiceContextV4 availabilityServiceContextV3) { String posURL = null; SplunkLogger splunkLogger = new SplunkLogger(availabilityServiceContextV3.getRequest().getHeaderRequest()); if (siteDTO.getPosType() != null) { if (siteDTO.getPosURL() != null && siteDTO.getPosURL().length() > 0 && siteDTO.getPosURL() .startsWith("http")) { posURL = siteDTO.getPosURL(); } else { if (siteDTO.getPosType().compareToIgnoreCase("TAMS") == 0) { String storeIP = nSightCache.getStoreIPMap().get(String.valueOf(storeNumber).substring(0, 3) .concat(String.valueOf(storeNumber).substring(5, 9))); if (storeIP != null) { posURL = "http://".concat(storeIP).concat(":8081/TamsService"); } else { LOGGER.error(splunkLogger.toString() + "StoreIP not found"); } } else { if (siteDTO.getPosType().compareToIgnoreCase("RPM") == 0) { //probably need to set it from the calling end } } } } else { LOGGER.error(splunkLogger.toString() + "PosType not found"); } return posURL; } private boolean isUsingRPMV2(SiteDTO siteDTO, AvailabilityServiceContextV4 availabilityServiceContextV3) { boolean isNewURL = false; //first check if we are in the pilot phase for RPM if (!nSightProperties.isUseRpmV2()) { String pilotStores = configManagementService.getPilotStoresV4(availabilityServiceContextV3,"RpmPricingPilot"); //// if there are pilot stores, use the new URL if (pilotStores != null && pilotStores.length() > 0) { final boolean[] pilotStoreExists = {false}; siteDTO.getSiteIdentifierList().forEach(siteIdentifier -> { if (siteIdentifier.getName().compareToIgnoreCase("9 Digit Store Number") == 0 && pilotStores.contains(siteIdentifier.getValue())) { pilotStoreExists[0] = true; } });//end of for if (pilotStoreExists[0] == true) { //then use the new URL isNewURL = true; } } else {///use the old URL isNewURL = false; } } else {//not in Pilot phase anymore, go with new URL isNewURL = true; } return isNewURL; } protected List setSupersedes(String msg, String superSedeType) { List superSedeList = new ArrayList(); if (superSedeType.equals("MISC")) { SuperSede superSede = new SuperSede(); superSede.setSuperSedeType(superSedeType); superSede.setMessage(msg); superSedeList.add(superSede); } else { String[] msgParts = msg.split(" "); int SuperSedesCount = msgParts.length == 4 ? 1 : 2; for (int i = 0; i < SuperSedesCount; i++) { SuperSede superSede = new SuperSede(); superSede.setSuperSedeType(superSedeType); if (i == 0) { superSede.setLineAbbrev(msgParts[2]); superSede.setPartNumber(msgParts[3]); } else { superSede.setLineAbbrev(msgParts[5]); superSede.setPartNumber(msgParts[6]); } superSedeList.add(superSede); } } return superSedeList; } }