package com.genpt.nsight.b2b.service.impl; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.dataformat.xml.XmlMapper; import com.genpt.nsight.NSightCache; import com.genpt.nsight.b2b.model.MultiStore.*; import com.genpt.nsight.b2b.service.MultiStorePartPriceAvailabilityService; import com.genpt.nsight.v1.SplunkLogger; import com.genpt.nsight.v1.model.*; import com.genpt.nsight.v1.model.dto.SiteDTO; import com.genpt.nsight.v4.AvailabilityServiceContextV4; import com.genpt.nsight.v4.service.ProductAvailabilityDetailServiceV4; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; @Service("MultiPartPriceAvailabilityService") public class MultiStorePartPriceAvailabilityServiceImpl implements MultiStorePartPriceAvailabilityService { @Autowired NSightCache nSightCache; private static final Logger LOGGER = LoggerFactory.getLogger(MultiStorePartPriceAvailabilityServiceImpl.class); private ProductAvailabilityDetailServiceV4 productAvailabilityDetailServiceV4; @Autowired public void setProductAvailabilityDetailServiceV4(ProductAvailabilityDetailServiceV4 productAvailabilityDetailServiceV4) { this.productAvailabilityDetailServiceV4 = productAvailabilityDetailServiceV4; } @Override public AvailabilityServiceContextV4 initializeContext(AvailabilityServiceContextV4 availabilityServiceContextV4, MultistorePriceAvailabilityRequestType request) { Requestor requestor = new Requestor(); String storeNumber = request.getStoreID(); String AccountName=""; if (storeNumber == null || storeNumber.trim().length()==0){ storeNumber = nSightCache.getBuyerIDMap().get(request.getBuyPartnerID()); if (storeNumber!=null && storeNumber.trim().length() >0) { String lines[] = storeNumber.split("\\|"); if (lines != null && lines.length > 0) { storeNumber = lines[0]; AccountName = lines[1]; } } }else { String tempStoreNumber = nSightCache.getBuyerIDMap().get(request.getBuyPartnerID()); if (tempStoreNumber!=null && tempStoreNumber.trim().length() >0) { String lines[] = tempStoreNumber.split("\\|"); if (lines != null && lines.length > 0) { AccountName = lines[1]; } } } requestor.setRequestorApplication("PartPriceAvailability"); requestor.setRequestorType("B2BLegacy"); RequestorIdentifier requestorIdentifier = new RequestorIdentifier(); requestorIdentifier.setType("9 Digit Store Number"); requestorIdentifier.setValue(storeNumber); requestor.setRequestorIdentifier(requestorIdentifier); Responder responder = new Responder(); responder.setResponderApplication("POS"); Security security = new Security(); UserCredentials userCredentials = new UserCredentials(); userCredentials.setPassword(request.getCustomerNumber()); userCredentials.setUserName("POS"); security.setUserCredentials(userCredentials); responder.setSecurity(security); HeaderRequest headerRequest = new HeaderRequest(); headerRequest.setRequestor(requestor); headerRequest.setResponder(responder); //headerRequest.setRequestID(); headerRequest.setCorrelationId(availabilityServiceContextV4.getCorrelationID()); //need to get the country code of the calling store headerRequest.setCountryCode(nSightCache.getAlpha2CountryCode(storeNumber)); headerRequest.setLanguageCode("EN"); headerRequest.setTimestamp(String.valueOf(System.currentTimeMillis())); com.genpt.nsight.v4.model.ActionRequest actionRequest = new com.genpt.nsight.v4.model.ActionRequest(); com.genpt.nsight.v4.model.Action action = new com.genpt.nsight.v4.model.Action(); action.setNeedProductQuantity(true); action.setNeedPricing(true); action.setNeedSuperSedes(true); action.setNeedDeliveryEstimateCutOffTimes(false); String callingStoreSIteID = nSightCache.getAliasToSiteIdMap().get(requestor.getRequestorIdentifier().getType() + "|" +storeNumber); if (callingStoreSIteID!=null && nSightCache.getCombinedFriendSet().contains(callingStoreSIteID)) action.setNeedCombinedInventory(true); actionRequest.setAction(action); com.genpt.nsight.v4.model.DetailRequest detailRequest = new com.genpt.nsight.v4.model.DetailRequest(); com.genpt.nsight.v4.model.InventoryRelationshipsRequested inventoryRelationshipsRequested = new com.genpt.nsight.v4.model.InventoryRelationshipsRequested(); inventoryRelationshipsRequested.setLocalStore(true); inventoryRelationshipsRequested.setServingDC(false); inventoryRelationshipsRequested.setAllOtherDCs(false); inventoryRelationshipsRequested.setAllSuppliers(false); OtherRelationShips otherRelationShips = new OtherRelationShips(); ArrayList arrayList= new ArrayList<>(); //arrayList.add("PROLink Inventory Friend"); arrayList.add("Store Console Inventory Friend"); if (callingStoreSIteID!=null && nSightCache.getCombinedFriendSet().contains(callingStoreSIteID)){ arrayList.add("Combined Inventory Friends"); } otherRelationShips.setRelationshipName(arrayList); inventoryRelationshipsRequested.setOtherRelationShips(otherRelationShips); detailRequest.setInventoryRelationshipsRequested(inventoryRelationshipsRequested); Set parts = new HashSet<>(); // the first check if we need to request DC Quantity is main counter if (availabilityServiceContextV4.isMainCounter()) inventoryRelationshipsRequested.setServingDC(true); //If its a Canadian store then its based on DCQTY or NODCBAL not present if (availabilityServiceContextV4.isNeedUAPDCQuantity()) inventoryRelationshipsRequested.setServingDC(true); for ( com.genpt.nsight.b2b.model.MultiStore.PartType b2bPart: request.getPart()){ com.genpt.nsight.v4.model.Part nsightPart = new com.genpt.nsight.v4.model.Part(); nsightPart.setLineAbbrev(b2bPart.getLineAbbrev()); nsightPart.setPartNumber(b2bPart.getPartNumber()); if (b2bPart.getPartMessage()!= null){ if (b2bPart.getPartMessage().compareToIgnoreCase("DCQTY")==0) inventoryRelationshipsRequested.setServingDC(true); } parts.add(nsightPart); } detailRequest.setParts(parts); com.genpt.nsight.v4.model.ProductAvailabilityRequest productAvailabilityRequest = new com.genpt.nsight.v4.model.ProductAvailabilityRequest(); productAvailabilityRequest.setActionRequest(actionRequest); productAvailabilityRequest.setDetailRequest(detailRequest); productAvailabilityRequest.setHeaderRequest(headerRequest); availabilityServiceContextV4.setRequest(productAvailabilityRequest); return availabilityServiceContextV4; } @Override public MultistorePriceAvailabilityResponseType getProductAvailability(AvailabilityServiceContextV4 availabilityServiceContextV4, MultistorePriceAvailabilityRequestType priceAvailabilityRequest) { SplunkLogger splunkLogger = new SplunkLogger(availabilityServiceContextV4.getRequest().getHeaderRequest()); long startTime = System.currentTimeMillis(); //create the response MultistorePriceAvailabilityResponseType priceAvailabilityResponse = new MultistorePriceAvailabilityResponseType(); MultistorePriceAvailabilityResponseType orderedpriceAvailabilityResponse = new MultistorePriceAvailabilityResponseType(); priceAvailabilityResponse.setStatusCode("0"); String storeNumber = priceAvailabilityRequest.getStoreID(); String AccountName=""; if (storeNumber == null || storeNumber.trim().length()==0){ storeNumber = nSightCache.getBuyerIDMap().get(priceAvailabilityRequest.getBuyPartnerID()); if (storeNumber!=null && storeNumber.trim().length() >0) { String lines[] = storeNumber.split("\\|"); if (lines != null && lines.length > 0) { storeNumber = lines[0]; AccountName = lines[1]; } } LOGGER.info(splunkLogger.toString() + " MultiPartPriceAvailabilityService, Store Number is null, using buyerpartnerID: {}, Corresponding Store Number is: {} ", priceAvailabilityRequest.getBuyPartnerID(), storeNumber); }else { String tempStoreNumber = nSightCache.getBuyerIDMap().get(priceAvailabilityRequest.getBuyPartnerID()); if (tempStoreNumber!=null && tempStoreNumber.trim().length() >0) { String lines[] = tempStoreNumber.split("\\|"); if (lines != null && lines.length > 0) { AccountName = lines[1]; } } } String siteId = nSightCache.getAliasToSiteIdMap().get("9 Digit Store Number" + "|" +storeNumber); boolean dontCallStore = false; if (storeNumber !=null ) nSightCache.getDontCallStoreSet().contains(String.valueOf(storeNumber).substring(0, 3).concat(String.valueOf(storeNumber).substring(5, 9))); if (siteId == null) { priceAvailabilityResponse.setStatusCode("1"); priceAvailabilityResponse.setStatusMessage("Unknown StoreID"); } else if (dontCallStore) { priceAvailabilityResponse.setStatusCode("99"); priceAvailabilityResponse.setStatusMessage("Store did not answer"); } else { NumberFormat df = DecimalFormat.getInstance(); df.setGroupingUsed(false); df.setMinimumFractionDigits(2); df.setMaximumFractionDigits(2); //Get the detail response first com.genpt.nsight.v4.model.ProductAvailabilityResponse productAvailabilityResponse = productAvailabilityDetailServiceV4.getProductAvailability(availabilityServiceContextV4, true); String storeAlias = null; if (availabilityServiceContextV4.isCallNonTAMS() && productAvailabilityResponse.getTracking().getIsSuccess()) { if (availabilityServiceContextV4.getRequestingSite().getStoreAlias() != null) storeAlias = availabilityServiceContextV4.getRequestingSite().getStoreAlias(); //iterate the parts HashSet partsFoundSet = new HashSet(); //go ahead and create the associated stores type AssociateStoresType associateStoresType = new AssociateStoresType(); //Create a hashmap to store the assocaiated stores HashMap associatedStoreMap = new HashMap<>(); int location = 0; for (String assocSiteID : availabilityServiceContextV4.getFromSiteIds()) { if (assocSiteID.compareToIgnoreCase(siteId) != 0) { AssociateStoreType associateStoreType = new AssociateStoreType(); SiteDTO siteDTO = nSightCache.getSiteIdToSiteMap().get(assocSiteID); for (SiteIdentifier siteIdentifier : siteDTO.getSiteIdentifierList()) { if (siteIdentifier.getName().compareToIgnoreCase("9 Digit Store Number") == 0 && siteDTO.getStoreAlias()!=null) { associateStoreType.setStoreID(siteIdentifier.getValue()); associateStoreType.setStoreAlias(siteDTO.getStoreAlias()); associateStoresType.getAssociateStore().add(associateStoreType); associatedStoreMap.put(assocSiteID, location); location++; break; } } } } //add the associated store to the AssociatedStores in response priceAvailabilityResponse.setAssociateStores(associateStoresType); for (com.genpt.nsight.v4.model.Part part : productAvailabilityResponse.getDetailResponse().getParts()) { PartPriceAvailabilityType partPriceAvailability = new PartPriceAvailabilityType(); //check for errors if (part.getTracking().getFault() != null) { priceAvailabilityResponse.setStatusCode(part.getTracking().getFault().getCode()); priceAvailabilityResponse.setStatusMessage(part.getTracking().getFault().getMessage()); priceAvailabilityResponse.setAssociateStores(null); break; } if (part.getPrice() != null && part.getPrice().getTracking().getFault() != null) { priceAvailabilityResponse.setStatusCode(part.getPrice().getTracking().getFault().getCode()); priceAvailabilityResponse.setStatusMessage(part.getPrice().getTracking().getFault().getMessage()); priceAvailabilityResponse.setAssociateStores(null); break; } boolean foundLocalStore= false; if (part.getSites()!=null) { for (Site site : part.getSites()) { if (site != null && site.getSiteType().compareToIgnoreCase("Store") == 0) { for (SiteRelationship siteRelationship : site.getSiteRelationships()) { if (siteRelationship.getSiteRelationshipType().compareToIgnoreCase("LocalStore") == 0) { foundLocalStore = true; break; } } } } } if (foundLocalStore == true && part.getSites() != null) {// found //need to check if quantities are populated in any sites for (Site sitePartFound : part.getSites()) { if (sitePartFound!=null && sitePartFound.getQuantity()!=null) { partsFoundSet.add(part.getLineAbbrev() + "-" + part.getPartNumber()); break; } } } if (foundLocalStore == true && part.getSites() != null && partsFoundSet.contains(part.getLineAbbrev() + "-" + part.getPartNumber())) { AssociateQtyType associateQtyType = new AssociateQtyType(); // create the response for all the quantities for assoc stores for (int i = 0; i < associatedStoreMap.size(); i++) { associateQtyType.getQtyOnHand().add("0.00"); } for (Site site : part.getSites()) { //Check if its local store for (SiteRelationship siteRelationship : site.getSiteRelationships()) { if (siteRelationship.getSiteRelationshipType().compareToIgnoreCase("LocalStore") == 0) { //create response for calling store // if (part.getLineAbbrev().trim().length()==2) // partPriceAvailability.setLineAbbrev(Strings.padEnd(part.getLineAbbrev().trim(), 3, ' ')); // else partPriceAvailability.setLineAbbrev(part.getLineAbbrev()); partPriceAvailability.setPartNumber(part.getPartNumber()); if (siteId != null && nSightCache.getCombinedFriendSet().contains(siteId)) partPriceAvailability.setQtyOnHand(df.format(site.getQuantity().getCombinedAvailability())); else partPriceAvailability.setQtyOnHand(df.format(site.getAvailableQuantity())); partPriceAvailability.setTAMSErrorMsg(""); if(site.getDeliveryTime()!= null) partPriceAvailability.setDeliveryTime(site.getDeliveryTime()); if(site.getPartAttributes()!=null && site.getPartAttributes().getPartDescription()!= null) partPriceAvailability.setPartDescription(site.getPartAttributes().getPartDescription()); //check if it has pricing if (part.getPrice() != null) { if (part.getPrice().getCustomerPrice() != null) { com.genpt.nsight.b2b.model.MultiStore.PriceType price = new com.genpt.nsight.b2b.model.MultiStore.PriceType(); if (part.getPrice().getListPrice()!=null) price.setListPrice(df.format(part.getPrice().getListPrice())); else price.setListPrice(""); // as per Gordon after a bunch of dots....... price.setPriceType("PRI"); if (part.getPrice().getCustomerPrice()!=null) price.setYourCost(df.format(part.getPrice().getCustomerPrice())); else price.setYourCost("");// as per Gordon after a bunch of dots....... partPriceAvailability.getPrice().add(price); } if (part.getPrice().getCoreCustomerPrice() != null) { com.genpt.nsight.b2b.model.MultiStore.PriceType price = new com.genpt.nsight.b2b.model.MultiStore.PriceType(); if (part.getPrice().getCoreListPrice()!=null) price.setListPrice(df.format(part.getPrice().getCoreListPrice())); else price.setListPrice("");// as per Gordon after a bunch of dots....... price.setPriceType("COR"); if (part.getPrice().getCoreCustomerPrice()!=null) price.setYourCost(df.format(part.getPrice().getCoreCustomerPrice())); else price.setYourCost("");// as per Gordon after a bunch of dots....... partPriceAvailability.getPrice().add(price); } if (part.getPrice().getMiscCharges() != null && part.getPrice().getMiscCharges().size() > 0) { for (MiscCharge miscCharge : part.getPrice().getMiscCharges()) { com.genpt.nsight.b2b.model.MultiStore.PriceType price = new com.genpt.nsight.b2b.model.MultiStore.PriceType(); price.setListPrice(df.format(miscCharge.getMiscListPrice())); price.setPriceType(miscCharge.getMiscType()); price.setYourCost(df.format(miscCharge.getMiscCustomerPrice())); partPriceAvailability.getPrice().add(price); } } } if (site.getSuperSedes() != null) { Map > superSedesMap = site.getSuperSedes().stream().collect(Collectors.groupingBy(SuperSede::getSuperSedeType)); superSedesMap.forEach((superSedeType,superSedes)->{ String msg = null; if(superSedeType.equals("MISC")) msg = superSedes.get(0).getMessage(); else msg = superSedes.stream().map(s -> s.getLineAbbrev()+ " " + s.getPartNumber()).collect(Collectors.joining(" and ")); //now set the supersede type switch (superSedeType) { case "SUPERSEDED_BY": partPriceAvailability.setTAMSErrorMsg("Superseded by " + msg); //superseded.setSupersedeType(1); break; case "REORDER": partPriceAvailability.setTAMSErrorMsg("Reorder as " + msg); //superseded.setSupersedeType(2); break; case "RENUMBERED": partPriceAvailability.setTAMSErrorMsg("Renumber as " + msg); //superseded.setSupersedeType(3); break; case "SUBSTITUTE": partPriceAvailability.setTAMSErrorMsg("Can use " + msg); //superseded.setSupersedeType(4); break; case "MISC": partPriceAvailability.setTAMSErrorMsg(msg); //superseded.setSupersedeType(4); break; default: partPriceAvailability.setTAMSErrorMsg("Sourced from alternate store " + msg); //superseded.setSupersedeType(5); } }); //partPriceAvailability.setSuperseded(superseded); } //priceAvailabilityResponse.getPartPriceAvailability().add(partPriceAvailability); } else if (siteRelationship.getSiteRelationshipType().compareToIgnoreCase("Primary DC") == 0) { partPriceAvailability.setDCBalanceQty(df.format(site.getAvailableQuantity())); } else {// its a associated store since we dont ask for Supplier data //associatedStoreMap.put(site.getSiteId().concat("|").concat(part.getLineAbbrev()).concat("|").concat(part.getPartNumber()),String.valueOf(site.getAvailableQuantity())); if(associatedStoreMap.get(site.getSiteId())!=null) associateQtyType.getQtyOnHand().set(associatedStoreMap.get(site.getSiteId()), df.format(site.getAvailableQuantity())); } } } if (associateQtyType.getQtyOnHand().size() > 0) { partPriceAvailability.setAssociateQty(associateQtyType); } //now add the logic for the combined DC quantity if (availabilityServiceContextV4.isCombineDCQuantity()) { if (partPriceAvailability.getdCBalanceQty() != null && partPriceAvailability.getdCBalanceQty().length() > 0) { float total = Float.parseFloat(partPriceAvailability.getQtyOnHand()) + Float.parseFloat(partPriceAvailability.getdCBalanceQty()); partPriceAvailability.setQtyOnHand(df.format(total)); //we also need to not set the DC quantity partPriceAvailability.setDCBalanceQty(null); } } priceAvailabilityResponse.getPartPriceAvailability().add(partPriceAvailability);//for each part }//if site is valid }//for parts //add the not found parts only if its a 0 Status if (priceAvailabilityResponse.getStatusCode().compareToIgnoreCase("0") == 0) { for (PartType requestPart : priceAvailabilityRequest.getPart()) { String key = requestPart.getLineAbbrev().trim() + "-" + requestPart.getPartNumber().trim(); if (!partsFoundSet.contains(key)) { //create the Partvailability entity PartPriceAvailabilityType partPriceAvailability = new PartPriceAvailabilityType(); // if (requestPart.getLineAbbrev().trim().length()==2) // partPriceAvailability.setLineAbbrev(Strings.padEnd(requestPart.getLineAbbrev().trim(), 3, ' ')); // else partPriceAvailability.setLineAbbrev(requestPart.getLineAbbrev().trim()); partPriceAvailability.setPartNumber(requestPart.getPartNumber()); partPriceAvailability.setTAMSErrorMsg("Part Not Found"); partPriceAvailability.setQtyOnHand("0.00"); priceAvailabilityResponse.getPartPriceAvailability().add(partPriceAvailability); } } StoreType storeType = new StoreType(); storeType.setStoreID(priceAvailabilityRequest.getStoreID()); priceAvailabilityResponse.setStore(storeType); } else { //add the associated store to the AssociatedStores in response } if (storeAlias != null && priceAvailabilityResponse.getStore() != null) { priceAvailabilityResponse.getStore().setStoreAlias(storeAlias); } // At this point we have the full response but we need to arrange the parts in the order of //parts in the request if (priceAvailabilityResponse.getStore() != null) orderedpriceAvailabilityResponse.setStore(priceAvailabilityResponse.getStore()); if (priceAvailabilityResponse.getAccount() != null) orderedpriceAvailabilityResponse.setAccount(priceAvailabilityResponse.getAccount()); if (priceAvailabilityResponse.getAssociateStores() != null) orderedpriceAvailabilityResponse.setAssociateStores(priceAvailabilityResponse.getAssociateStores()); if (priceAvailabilityResponse.getStatusCode() != null) orderedpriceAvailabilityResponse.setStatusCode(priceAvailabilityResponse.getStatusCode()); if (priceAvailabilityResponse.getStatusMessage() != null) orderedpriceAvailabilityResponse.setStatusMessage(priceAvailabilityResponse.getStatusMessage()); for (PartType requestPart : priceAvailabilityRequest.getPart()) { for (PartPriceAvailabilityType partPriceAvailabilityType : priceAvailabilityResponse.getPartPriceAvailability()) { if (partPriceAvailabilityType.getLineAbbrev().trim().compareToIgnoreCase(requestPart.getLineAbbrev().trim()) == 0 && partPriceAvailabilityType.getPartNumber().trim().compareToIgnoreCase(requestPart.getPartNumber().trim()) == 0) { orderedpriceAvailabilityResponse.getPartPriceAvailability().add(partPriceAvailabilityType); break; } } }//could not make a call to the store }else{ priceAvailabilityResponse.setStatusCode("2"); priceAvailabilityResponse.setStatusMessage("Store did not answer"); } }//valid data from getparts XmlMapper xmlMapper = new XmlMapper(); String requestAsString = null; try { requestAsString = xmlMapper.writeValueAsString(orderedpriceAvailabilityResponse); LOGGER.info(splunkLogger.toString() + " MultiPartPriceAvailabilityService : {} ", requestAsString); } catch (JsonProcessingException e) { e.printStackTrace(); } LOGGER.info(splunkLogger.toString() + " Total time within MultiPartPriceAvailabilityService = {}", System.currentTimeMillis() - startTime); if (priceAvailabilityResponse.getStatusCode().compareToIgnoreCase("0")==0) { if (AccountName != null && AccountName.length()>0) orderedpriceAvailabilityResponse.setAccount(AccountName); if (storeNumber!= null && storeNumber.length() > 0) orderedpriceAvailabilityResponse.getStore().setStoreID(storeNumber); return orderedpriceAvailabilityResponse; } else return priceAvailabilityResponse; } }