package com.genpt.nsight.v3.service.impl; 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.v2.model.DetailRequest; import com.genpt.nsight.v2.service.POSService; import com.genpt.nsight.v3.service.AvailabilityServiceContextV3; import com.genpt.nsight.v3.service.ConfigManagementService; import com.genpt.nsight.v3.service.InventoryServiceV3; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; 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.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.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.stream.Collectors; @Service("InventoryServiceV3") public class InventoryServiceV3Impl implements InventoryServiceV3 { @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(InventoryServiceV3Impl.class); private ListeningExecutorService posServiceExecutor; JAXBContext context = null; JAXBContext rpmContext = null; JAXBContext uapContext = null; @Autowired NSightProperties nSightProperties; @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); posServiceExecutor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(nSightProperties.getPosServiceThreads())); context = JAXBContext.newInstance(ServiceRequest.class); rpmContext = JAXBContext.newInstance(PriceAvailabilityRequest.class); uapContext = JAXBContext.newInstance(MultiPartInquiryRequestType.class); } @Override public void preparePartList(AvailabilityServiceContextV3 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(); ) { 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 = nSightCache.getProductKitMap().get(fullPartNumber); if (productKit != null) { productKit.getKitComponents().forEach(kitComponent -> { Part virtualPart = new 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(AvailabilityServiceContextV3 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; } @Override public void setNonNapaInventoryFutures(AvailabilityServiceContextV3 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()); //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) || (siteDTO.getPosType() !=null && siteDTO.getPosType().compareToIgnoreCase("NON NAPA")==0) || (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().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()); //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(AvailabilityServiceContextV3 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 //we should still make a call to nsight and the store and then merge the 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(AvailabilityServiceContextV3 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))) { Part part = new 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); Site site = new 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()) { Part inputPartKey = availabilityServiceContextV3.getInputParts().get(partKey); Part inputPart = new Part(); inputPart.setLineAbbrev(inputPartKey.getLineAbbrev()); inputPart.setPartNumber(inputPartKey.getPartNumber()); Site site = new 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 void processInventoryFutures(AvailabilityServiceContextV3 availabilityServiceContextV3) { SplunkLogger splunkLogger = new SplunkLogger(availabilityServiceContextV3.getRequest().getHeaderRequest()); 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; } //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))) { Part part = new Part(); partNumber = row.getString("part_number"); part.setPartNumber(partNumber); part.setLineAbbrev(lineAbbrev); Site site = new 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, Message : {}, StackTrace: {} ", availabilityServiceContextV3.getApplicationID(), availabilityServiceContextV3.getCorrelationID(), e.getMessage(), e.getStackTrace()); } return parts.stream(); }).collect(Collectors.groupingBy(p -> p.getPartNumber() + "-" + p.getLineAbbrev())); availabilityServiceContextV3.setInventory(inventoryMap); } private String constructPOSUrl(SiteDTO siteDTO ,String storeNumber, AvailabilityServiceContextV3 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, AvailabilityServiceContextV3 availabilityServiceContextV3){ boolean isNewURL = false; //first check if we are in the pilot phase for RPM if (!nSightProperties.isUseRpmV2()) { String pilotStores = configManagementService.getPilotStoresV3(availabilityServiceContextV3); //// 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