Rev 29940 | Rev 30121 | Go to most recent revision | View as "text/plain" | Blame | Compare with Previous | Last modification | View Log | RSS feed
package com.spice.profitmandi.service.scheme;import com.spice.profitmandi.common.enumuration.ItemType;import com.spice.profitmandi.common.enumuration.MessageType;import com.spice.profitmandi.common.exception.ProfitMandiBusinessException;import com.spice.profitmandi.common.model.ProfitMandiConstants;import com.spice.profitmandi.common.model.SchemeModel;import com.spice.profitmandi.common.model.SendNotificationModel;import com.spice.profitmandi.common.services.ReporticoService;import com.spice.profitmandi.common.util.FormattingUtils;import com.spice.profitmandi.common.util.StringUtils;import com.spice.profitmandi.dao.entity.catalog.Item;import com.spice.profitmandi.dao.entity.catalog.Scheme;import com.spice.profitmandi.dao.entity.fofo.*;import com.spice.profitmandi.dao.entity.transaction.PriceDrop;import com.spice.profitmandi.dao.enumuration.catalog.AmountType;import com.spice.profitmandi.dao.enumuration.catalog.SchemeType;import com.spice.profitmandi.dao.enumuration.fofo.ScanType;import com.spice.profitmandi.dao.enumuration.transaction.SchemePayoutStatus;import com.spice.profitmandi.dao.model.CreateSchemeRequest;import com.spice.profitmandi.dao.repository.catalog.ItemRepository;import com.spice.profitmandi.dao.repository.catalog.SchemeRepository;import com.spice.profitmandi.dao.repository.catalog.TagListingRepository;import com.spice.profitmandi.dao.repository.dtr.RetailerRepository;import com.spice.profitmandi.dao.repository.fofo.*;import com.spice.profitmandi.dao.repository.transaction.PriceDropRepository;import com.spice.profitmandi.service.NotificationService;import com.spice.profitmandi.service.authentication.RoleManager;import com.spice.profitmandi.service.inventory.PurchaseService;import com.spice.profitmandi.service.wallet.WalletService;import in.shop2020.model.v1.order.WalletReferenceType;import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.query.Query;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.cache.annotation.Cacheable;import org.springframework.stereotype.Component;import javax.persistence.criteria.CriteriaBuilder;import javax.persistence.criteria.CriteriaQuery;import javax.persistence.criteria.Predicate;import javax.persistence.criteria.Root;import java.text.MessageFormat;import java.time.LocalDate;import java.time.LocalDateTime;import java.time.YearMonth;import java.util.*;import java.util.stream.Collectors;@Componentpublic class SchemeServiceImpl implements SchemeService {private static final Logger LOGGER = LogManager.getLogger(SchemeServiceImpl.class);@Autowired@Qualifier("fofoInventoryItemRepository")private InventoryItemRepository inventoryItemRepository;@Autowiredprivate ActivatedImeiRepository activatedImeiRepository;@Autowiredprivate PartnerTypeChangeService partnerTypeChangeService;@Autowiredprivate PurchaseService purchaseService;@Autowiredprivate ScanRecordRepository scanRecordRepository;@Autowiredprivate SessionFactory sessionFactory;private Set<Integer> tagIds = new HashSet<Integer>(Arrays.asList(4));@Autowiredprivate SchemeRepository schemeRepository;@Autowiredprivate PriceDropRepository priceDropRepository;@Autowiredprivate RoleManager roleManager;@Autowiredprivate RetailerRepository retailerRepository;@Autowiredprivate ReporticoService reporticoService;@Autowiredprivate TagListingRepository tagListingRepository;@Autowiredprivate SchemeInOutRepository schemeInOutRepository;@Autowired@Qualifier("catalogItemRepository")private ItemRepository itemRepository;@Autowiredprivate SchemeItemRepository schemeItemRepository;@Autowiredprivate WalletService walletService;@Autowiredprivate FofoOrderItemRepository fofoOrderItemRepository;@Autowiredprivate FofoLineItemRepository fofoLineItemRepository;@Autowiredprivate PurchaseRepository purchaseRepository;@Autowiredprivate FofoOrderRepository fofoOrderRepository;@Overridepublic void saveScheme(int creatorId, CreateSchemeRequest createSchemeRequest) throws ProfitMandiBusinessException {this.validateCreateSchemeRequest(createSchemeRequest);Scheme scheme = this.toScheme(creatorId, createSchemeRequest);if (scheme.getStartDateTime().isAfter(scheme.getEndDateTime())) {throw new ProfitMandiBusinessException(ProfitMandiConstants.START_DATE + ", " + ProfitMandiConstants.END_DATE,scheme.getStartDateTime() + ", " + scheme.getEndDateTime(), "SCHM_VE_1005");}// this.validateItemIds(createSchemeRequest);schemeRepository.persist(scheme);for (int itemId : createSchemeRequest.getItemIds()) {SchemeItem schemeItem = new SchemeItem();schemeItem.setSchemeId(scheme.getId());schemeItem.setItemId(itemId);schemeItemRepository.persist(schemeItem);}}private void validateCreateSchemeRequest(CreateSchemeRequest createSchemeRequest)throws ProfitMandiBusinessException {if (createSchemeRequest.getName() == null || createSchemeRequest.getName().isEmpty()) {throw new ProfitMandiBusinessException(ProfitMandiConstants.NAME, createSchemeRequest.getName(),"SCHM_VE_1000");}if (createSchemeRequest.getAmount() <= 0) {throw new ProfitMandiBusinessException(ProfitMandiConstants.AMOUNT, createSchemeRequest.getAmount(),"SCHM_VE_1001");}if (createSchemeRequest.getAmountType().equals(AmountType.PERCENTAGE)&& createSchemeRequest.getAmount() > 100) {throw new ProfitMandiBusinessException(ProfitMandiConstants.AMOUNT, createSchemeRequest.getAmount(),"SCHM_VE_1002");}if (createSchemeRequest.getStartDate() == null) {throw new ProfitMandiBusinessException(ProfitMandiConstants.START_DATE, createSchemeRequest.getStartDate(),"SCHM_VE_1003");}if (createSchemeRequest.getEndDate() == null) {throw new ProfitMandiBusinessException(ProfitMandiConstants.END_DATE, createSchemeRequest.getEndDate(),"SCHM_VE_1004");}}private Scheme toScheme(int creatorId, CreateSchemeRequest createSchemeRequest) {Scheme scheme = new Scheme();scheme.setName(createSchemeRequest.getName());scheme.setDescription(createSchemeRequest.getDescription());scheme.setType(createSchemeRequest.getType());scheme.setAmountType(createSchemeRequest.getAmountType());scheme.setAmount(createSchemeRequest.getAmount());scheme.setPartnerType(createSchemeRequest.getPartnerType());scheme.setStartDateTime(createSchemeRequest.getStartDate());scheme.setEndDateTime(createSchemeRequest.getEndDate());scheme.setCreatedBy(creatorId);scheme.setCashback(createSchemeRequest.isCashback());return scheme;}private void validateItemIds(CreateSchemeRequest createSchemeRequest) throws ProfitMandiBusinessException {if (createSchemeRequest.getItemIds() == null || createSchemeRequest.getItemIds().isEmpty()) {throw new ProfitMandiBusinessException(ProfitMandiConstants.ITEM_ID, createSchemeRequest.getItemIds(),"SCHM_1003");}List<Integer> foundItemIds = itemRepository.selectIdsByIdsAndType(createSchemeRequest.getItemIds(),ItemType.SERIALIZED);if (foundItemIds.size() != createSchemeRequest.getItemIds().size()) {createSchemeRequest.getItemIds().removeAll(foundItemIds);throw new ProfitMandiBusinessException(ProfitMandiConstants.ITEM_ID, createSchemeRequest.getItemIds(),"SCHM_1004");}}@Overridepublic Scheme getSchemeById(int schemeId) throws ProfitMandiBusinessException {Scheme scheme = schemeRepository.selectById(schemeId);List<Integer> itemIds = schemeItemRepository.selectItemIdsBySchemeId(scheme.getId());if (itemIds.size() > 0) {List<Item> items = itemRepository.selectByIds(new HashSet<>(itemIds));scheme.setItemStringMap(this.toItemStringMap(items));}return scheme;}public Map<Integer, String> toItemStringMap(List<Item> items) {Map<Integer, String> itemMap = new HashMap<>();for (Item item : items) {itemMap.put(item.getId(), this.getItemString(item));}return itemMap;}public String getItemString(Item item) {StringBuilder itemString = new StringBuilder();if (item.getBrand() != null && !item.getBrand().isEmpty()) {itemString.append(item.getBrand().trim());}itemString.append(" ");if (item.getModelName() != null && !item.getModelName().isEmpty()) {itemString.append(item.getModelName().trim());}itemString.append(" ");if (item.getModelNumber() != null && !item.getModelNumber().isEmpty()) {itemString.append(item.getModelNumber().trim());}itemString.append(" ");if (item.getColor() != null && !item.getColor().isEmpty()) {itemString.append(item.getColor().trim());}return itemString.toString();}private Set<Integer> schemeItemsToItemIds(List<SchemeItem> schemeItems) {Set<Integer> itemIds = new HashSet<>();for (SchemeItem schemeItem : schemeItems) {itemIds.add(schemeItem.getItemId());}return itemIds;}@Overridepublic List<SchemeModel> getAllSchemeModels(LocalDateTime startDateTime, LocalDateTime endDateTime) {List<Scheme> schemes = schemeRepository.selectAllBetweenCreateTimestamp(startDateTime, endDateTime);Map<Integer, Scheme> schemeIdSchemeMap = this.toSchemeIdSchemeMap(schemes);List<SchemeItem> schemeItems = schemeItemRepository.selectBySchemeIds(schemeIdSchemeMap.keySet());Set<Integer> itemIds = this.schemeItemsToItemIds(schemeItems);List<Item> items = itemRepository.selectByIds(itemIds);Map<Integer, String> itemStringMap = this.toItemStringMap(items);this.addItemIdsToSchemes(schemeItems, schemeIdSchemeMap, itemStringMap);return this.toSchemeModels(schemeIdSchemeMap);}@AutowiredNotificationService notificationService;private List<SchemeModel> toSchemeModels(Map<Integer, Scheme> schemeIdSchemeMap) {List<SchemeModel> schemeModels = new ArrayList<>();for (Map.Entry<Integer, Scheme> schemeIdSchemeEntry : schemeIdSchemeMap.entrySet()) {schemeModels.add(this.toSchemeModel(schemeIdSchemeEntry.getValue()));}return schemeModels;}private SchemeModel toSchemeModel(Scheme scheme) {SchemeModel schemeModel = new SchemeModel();schemeModel.setSchemeId(scheme.getId());schemeModel.setName(scheme.getName());schemeModel.setDescription(scheme.getDescription());schemeModel.setSchemeType(scheme.getType().toString());schemeModel.setAmountType(scheme.getAmountType().toString());schemeModel.setAmount(scheme.getAmount());schemeModel.setStartDateTime(StringUtils.toString(scheme.getStartDateTime()));schemeModel.setEndDateTime(StringUtils.toString(scheme.getEndDateTime()));schemeModel.setCreateTimestamp(StringUtils.toString(scheme.getCreateTimestamp()));schemeModel.setActiveTimestamp(StringUtils.toString(scheme.getActiveTimestamp()));schemeModel.setExpireTimestamp(StringUtils.toString(scheme.getExpireTimestamp()));schemeModel.setCreatedBy(scheme.getCreatedBy());schemeModel.setItemStringMap(scheme.getItemStringMap());schemeModel.setRetailerIds(scheme.getRetailerIds());return schemeModel;}private void addItemIdsToSchemes(List<SchemeItem> schemeItems, Map<Integer, Scheme> schemeIdSchemeMap,Map<Integer, String> itemStringMap) {for (SchemeItem schemeItem : schemeItems) {schemeIdSchemeMap.get(schemeItem.getSchemeId()).getItemStringMap().put(schemeItem.getItemId(),itemStringMap.get(schemeItem.getItemId()));}}@Overridepublic void activeSchemeById(int schemeId) throws ProfitMandiBusinessException {Scheme scheme = schemeRepository.selectById(schemeId);if (scheme.getActiveTimestamp() != null) {throw new ProfitMandiBusinessException(ProfitMandiConstants.ACTIVE_TIMESTAMP, scheme.getActiveTimestamp(),"SCHM_1005");}if (scheme.getExpireTimestamp() != null) {throw new ProfitMandiBusinessException(ProfitMandiConstants.EXPIRE_TIMESTAMP, scheme.getExpireTimestamp(),"SCHM_1006");}scheme.setActiveTimestamp(LocalDateTime.now());this.sendSchemeNotification(scheme);/** if (scheme.getType() == SchemeType.IN) {* this.processPreviousPurchases(scheme); } else if (scheme.getType() ==* SchemeType.OUT) { this.processPreviousSales(scheme); }*/}private void sendSchemeNotification(Scheme scheme) throws ProfitMandiBusinessException {if (scheme.getType().equals(SchemeType.ACTIVATION)) {SendNotificationModel sendNotificationModel = new SendNotificationModel();List<SchemeItem> schemeItems = schemeItemRepository.selectBySchemeIds(Collections.singleton(scheme.getId()));Set<Integer> itemIds = schemeItems.stream().map(x -> x.getItemId()).collect(Collectors.toSet());List<String> itemDescriptions = itemRepository.selectByIds(itemIds).stream().map(x -> x.getItemDescriptionNoColor()).distinct().collect(Collectors.toList());String title = "Activation scheme of Rs." + FormattingUtils.formatDecimal(scheme.getAmount()) + " for " + String.join(", ", itemDescriptions);String message = "Duration from - " + FormattingUtils.formatDateMonth(scheme.getStartDateTime()) + " - " + FormattingUtils.formatDateMonth(scheme.getEndDateTime());sendNotificationModel.setCampaignName("activationscheme");sendNotificationModel.setUrl("https://app.smartdukaan.com/pages/home/scheme/" + scheme.getId());sendNotificationModel.setExpiresat(LocalDateTime.now().plusDays(1));sendNotificationModel.setMessage(message);sendNotificationModel.setTitle(title);sendNotificationModel.setType("url");sendNotificationModel.setMessageType(MessageType.scheme);notificationService.sendNotificationToAll(sendNotificationModel);}}@Overridepublic void expireSchemeById(int schemeId, LocalDateTime expiryTime) throws ProfitMandiBusinessException {Scheme scheme = schemeRepository.selectById(schemeId);if (scheme == null || scheme.getActiveTimestamp() == null) {throw new ProfitMandiBusinessException(ProfitMandiConstants.ACTIVE_TIMESTAMP, scheme.getActiveTimestamp(),"SCHM_1007");}if (scheme.getExpireTimestamp() != null) {throw new ProfitMandiBusinessException(ProfitMandiConstants.EXPIRE_TIMESTAMP, scheme.getExpireTimestamp(),"SCHM_1008");}scheme.setExpireTimestamp(LocalDateTime.now());if (expiryTime.isAfter(scheme.getEndDateTime())) {throw new ProfitMandiBusinessException(ProfitMandiConstants.EXPIRE_TIMESTAMP, scheme.getExpireTimestamp(),"End Date cant be extended during expiry");}scheme.setEndDateTime(expiryTime);schemeRepository.persist(scheme);}private Map<Integer, Scheme> toSchemeIdSchemeMap(List<Scheme> schemes) {Map<Integer, Scheme> schemeIdSchemeMap = new HashMap<>();for (Scheme scheme : schemes) {schemeIdSchemeMap.put(scheme.getId(), scheme);}return schemeIdSchemeMap;}private Set<Integer> inventoryItemsToItemIds(List<InventoryItem> inventoryItems) {Set<Integer> itemIds = new HashSet<>();for (InventoryItem inventoryItem : inventoryItems) {itemIds.add(inventoryItem.getItemId());}return itemIds;}private Map<Integer, Set<Scheme>> toItemIdSchemesMap(List<SchemeItem> schemeItems, List<Scheme> schemes) {Map<Integer, Scheme> schemeIdSchemesMap = this.toSchemeIdSchemeMap(schemes);Map<Integer, Set<Scheme>> itemIdSchemesMap = new HashMap<>();for (SchemeItem schemeItem : schemeItems) {if (!itemIdSchemesMap.containsKey(schemeItem.getItemId())) {Set<Scheme> schemesSet = new HashSet<>();schemesSet.add(schemeIdSchemesMap.get(schemeItem.getSchemeId()));itemIdSchemesMap.put(schemeItem.getItemId(), schemesSet);} else {itemIdSchemesMap.get(schemeItem.getItemId()).add(schemeIdSchemesMap.get(schemeItem.getSchemeId()));}}return itemIdSchemesMap;}private Map<InventoryItem, Set<Scheme>> toInventoryItemSchemesMap(List<Scheme> schemes,List<InventoryItem> inventoryItems) {Set<Integer> schemeIds = new HashSet<>();for (Scheme scheme : schemes) {schemeIds.add(scheme.getId());}Set<Integer> itemIds = this.inventoryItemsToItemIds(inventoryItems);List<SchemeItem> schemeItems = schemeItemRepository.selectBySchemeIdsAndItemIds(schemeIds, itemIds);Map<Integer, Set<Scheme>> itemIdSchemesMap = this.toItemIdSchemesMap(schemeItems, schemes);Map<InventoryItem, Set<Scheme>> inventoryItemSchemsMap = new HashMap<>();for (InventoryItem inventoryItem : inventoryItems) {if (itemIdSchemesMap.containsKey(inventoryItem.getItemId())) {inventoryItemSchemsMap.put(inventoryItem, itemIdSchemesMap.get(inventoryItem.getItemId()));}}return inventoryItemSchemsMap;}@Overridepublic void processSchemeIn(int purchaseId, int retailerId) throws ProfitMandiBusinessException {LOGGER.info("Trying to process SchemeIn with purchaseId [{}] and retailerId [{}]", purchaseId, retailerId);Purchase purchase = purchaseRepository.selectByIdAndFofoId(purchaseId, retailerId);// TODO - SCHEMEPartnerType partnerType = partnerTypeChangeService.getTypeOnMonth(retailerId,YearMonth.from(purchase.getCreateTimestamp()));// PartnerType partnerType = partnerTypeChangeService.getTypeOnDate(retailerId,// purchase.getCreateTimestamp().toLocalDate());List<Scheme> schemes = schemeRepository.selectActiveAll(Arrays.asList(SchemeType.IN), partnerType,purchase.getCreateTimestamp(), false);float totalCashback = 0;if (schemes.isEmpty()) {return;}List<InventoryItem> inventoryItems = inventoryItemRepository.selectByPurchaseId(purchaseId);Set<Integer> itemIds = inventoryItems.stream().map(x -> x.getItemId()).collect(Collectors.toSet());LocalDateTime billingDate = purchaseService.getBillingDateOfPurchase(purchaseId);Set<Integer> itemIdsSet = tagListingRepository.selectByItemIdsAndTagIds(itemIds, tagIds).stream().filter(x -> x.getEolDate() == null || x.getEolDate().isAfter(billingDate)).map(x -> x.getItemId()).collect(Collectors.toSet());// Only consider inventory items that were not returnedinventoryItems = inventoryItems.stream().filter(x -> itemIdsSet.contains(x.getItemId())).filter(x -> !x.getLastScanType().equals(ScanType.PURCHASE_RET_BAD)).filter(x -> !x.getLastScanType().equals(ScanType.PURCHASE_RET)).collect(Collectors.toList());LOGGER.info(inventoryItems);if (inventoryItems.size() == 0)return;Map<InventoryItem, Set<Scheme>> inventoryItemSchemesMap = this.toInventoryItemSchemesMap(schemes,inventoryItems);if (inventoryItemSchemesMap.isEmpty()) {return;}Map<InventoryItem, Set<Scheme>> allInventoryItemSchemesMap = new HashMap<>();for (Map.Entry<InventoryItem, Set<Scheme>> inventoryItemSchemesEntry : inventoryItemSchemesMap.entrySet()) {Set<Scheme> allSchemes = new HashSet<>();for (Scheme scheme : inventoryItemSchemesEntry.getValue()) {allSchemes.add(scheme);}allInventoryItemSchemesMap.put(inventoryItemSchemesEntry.getKey(), allSchemes);}//int itemsCount = 0;for (Map.Entry<InventoryItem, Set<Scheme>> allInventoryItemSchemesEntry : allInventoryItemSchemesMap.entrySet()) {float inventoryItemCashback = 0;for (Scheme scheme : allInventoryItemSchemesEntry.getValue()) {InventoryItem inventoryItem = allInventoryItemSchemesEntry.getKey();float cashback = this.createSchemeInOut(scheme, inventoryItem);inventoryItemCashback += cashback;}if (inventoryItemCashback > 0) {totalCashback += inventoryItemCashback;itemsCount++;}}LOGGER.info("Items count for purchase id {} is {}", purchaseId, itemsCount);if (itemsCount > 0) {walletService.addAmountToWallet(retailerId, purchaseId, WalletReferenceType.SCHEME_IN, "Added for SCHEME IN against invoice "+ purchase.getPurchaseReference() + " (total " + itemsCount + " pcs)",totalCashback, purchase.getCreateTimestamp());LOGGER.info("Added Rs.{} for SCHEME IN against invoice {} total pcs({}) {}", totalCashback,purchase.getPurchaseReference(), itemsCount);purchase.setCashback(purchase.getCashback() + totalCashback);purchaseRepository.persist(purchase);}}//Only in and activation margins are allowed to be rolled out more than twiceprivate float createSchemeInOut(Scheme scheme, InventoryItem inventoryItem) {LOGGER.info("Scheme === {}", scheme);if ((scheme.getId() == 411 || scheme.getId() == 612) && inventoryItem.getCreateTimestamp().isAfter(LocalDate.of(2021, 12, 1).atStartOfDay())) {return 0;}List<SchemeInOut> sios = schemeInOutRepository.selectAllByType(scheme.getType(), inventoryItem.getId());float actualCredit = 0;if (sios.stream().filter(x -> x.getRolledBackTimestamp() == null && x.getSchemeId() == scheme.getId()).collect(Collectors.toList()).size() == 0) {sios = sios.stream().filter(x -> x.getRolledBackTimestamp() == null).collect(Collectors.toList());//Rejected Scheme for types INVESTMENT and ACTIVATION are considered rolledback only if the item billing is cancelled.float amountCredited = (float) sios.stream().mapToDouble(e -> e.getAmount()).sum();LOGGER.info("SIOS ===== {}", sios);float amountToCredit = this.getAmount(inventoryItem, scheme);//Activation and in schemeif (!scheme.getType().equals(SchemeType.IN) && !scheme.getType().equals(SchemeType.ACTIVATION) && sios.size() > 0) {if (sios.size() > 1) {LOGGER.info("SAMESCHEMETYPE has already been credited twice for inventoryItem - {}", inventoryItem.getId());return 0;}if (amountToCredit > amountCredited + 1f) {for (SchemeInOut sio : sios) {sio.setRolledBackTimestamp(LocalDateTime.now());sio.setStatus(SchemePayoutStatus.REJECTED);sio.setStatusDescription("Partner Category upgraded, new entry added");}actualCredit = amountToCredit - amountCredited;} else {return 0;}} else {actualCredit = amountToCredit;}LOGGER.info("Actual Credit ==== {}", actualCredit);SchemeInOut schemeInOut = new SchemeInOut();schemeInOut.setSchemeId(scheme.getId());schemeInOut.setInventoryItemId(inventoryItem.getId());schemeInOut.setAmount(amountToCredit);schemeInOutRepository.persist(schemeInOut);if (scheme.getType().equals(SchemeType.ACTIVATION)) {schemeInOut.setStatus(SchemePayoutStatus.PENDING);schemeInOut.setStatusDescription("Activation pending for IMEI#" + inventoryItem.getSerialNumber());return 0;} else if (scheme.getType().equals(SchemeType.INVESTMENT)) {schemeInOut.setStatus(SchemePayoutStatus.PENDING);schemeInOut.setStatusDescription("Subject to investment days maintained");return 0;} else {schemeInOut.setStatus(SchemePayoutStatus.CREDITED);if (scheme.getType().equals(SchemeType.IN)) {schemeInOut.setStatusDescription("Credited for GRN of IMEI#" + inventoryItem.getSerialNumber());} else if (SchemeService.OUT_SCHEME_TYPES.contains(scheme.getType())) {schemeInOut.setStatusDescription("Credited for sale of IMEI#" + inventoryItem.getSerialNumber());}schemeInOut.setCreditTimestamp(LocalDateTime.now());}}return actualCredit;}// We are maintaining price drop after grnprivate float getAmount(InventoryItem inventoryItem, Scheme scheme) {float amount = 0;float dpForCalc = 0;float taxableSellingPrice = 0;// float totalTaxRate = inventoryItem.getIgstRate() +// inventoryItem.getSgstRate() + inventoryItem.getCgstRate();// Hardcoding it to 18%float totalTaxRate = 18f;// float totalTaxRate = inventoryItem.getIgstRate() +// inventoryItem.getSgstRate() + inventoryItem.getCgstRate();if (scheme.getAmountType() == AmountType.PERCENTAGE) {if (scheme.getType().equals(SchemeType.IN)) {dpForCalc = inventoryItem.getUnitPrice() - inventoryItem.getPriceDropAmount();} else {try {dpForCalc = Math.min(inventoryItem.getUnitPrice() - inventoryItem.getPriceDropAmount(),tagListingRepository.selectByItemId(inventoryItem.getItemId()).getSellingPrice());} catch (Exception e) {LOGGER.info("Could not find tag Listing entry in {}", inventoryItem.getItemId());e.printStackTrace();}}taxableSellingPrice = dpForCalc / (1 + totalTaxRate / 100);amount = taxableSellingPrice * scheme.getAmount() / 100;System.out.println(String.format("%d\t%s\t%d\t%d\t%s\t%s\t%s\t%s\t%f\t%f\t%f\t%f", inventoryItem.getId(),inventoryItem.getSerialNumber(), inventoryItem.getItemId(), scheme.getId(), scheme.getName(),scheme.getType(), scheme.getAmountType(), scheme.getPartnerType(), dpForCalc, taxableSellingPrice,scheme.getAmount(), amount));} else {amount = scheme.getAmount();System.out.println(String.format("%d\t%s\t%d\t%d\t%s\t%s\t%s\t%s\t%f\t%f\t%d\t%f", inventoryItem.getId(),inventoryItem.getSerialNumber(), inventoryItem.getItemId(), scheme.getId(), scheme.getName(),scheme.getType(), scheme.getAmountType(), scheme.getPartnerType(), dpForCalc, taxableSellingPrice,0, amount));}return amount;}@Overridepublic void processSchemeOut(int fofoOrderId, int retailerId) throws ProfitMandiBusinessException {FofoOrder fofoOrder = fofoOrderRepository.selectByFofoIdAndOrderId(retailerId, fofoOrderId);// Process only if order is not cancelledif (fofoOrder.getCancelledTimestamp() == null) {// PartnerType partnerType = partnerTypeChangeService.getTypeOnDate(retailerId,// fofoOrder.getCreateTimestamp().toLocalDate());// TODO - SCHEMEPartnerType partnerType = partnerTypeChangeService.getTypeOnMonth(retailerId,YearMonth.from(fofoOrder.getCreateTimestamp()));List<ScanRecord> scanRecords = scanRecordRepository.selectAllByOrderId(fofoOrderId);Set<Integer> inventoryItemIds = scanRecords.stream().map(x -> x.getInventoryItemId()).collect(Collectors.toSet());Set<InventoryItem> inventoryItems = inventoryItemRepository.selectByIds(inventoryItemIds).stream().filter(x -> x.getSerialNumber() != null && !x.getSerialNumber().equals("")).collect(Collectors.toSet());if (inventoryItems.size() == 0) {return;}Set<Integer> itemIds = inventoryItems.stream().map(x -> x.getItemId()).collect(Collectors.toSet());// Remove Items that are eol now.Set<Integer> itemIdsSet = tagListingRepository.selectByItemIdsAndTagIds(itemIds, tagIds).stream().filter(x -> x.getEolDate() == null || x.getEolDate().isAfter(fofoOrder.getCreateTimestamp())).map(x -> x.getItemId()).collect(Collectors.toSet());// Only consider inventory items that were not returnedinventoryItems = inventoryItems.stream().filter(x -> itemIdsSet.contains(x.getItemId())).collect(Collectors.toSet());if (inventoryItems.size() == 0) {return;}float totalCashback = 0;int count = 0;List<SchemeType> allOutSchemeTypes = new ArrayList<>();allOutSchemeTypes.addAll(Arrays.asList(SchemeType.ACTIVATION, SchemeType.INVESTMENT));allOutSchemeTypes.addAll(OUT_SCHEME_TYPES);List<Scheme> allActiveSchemes = schemeRepository.selectActiveAll(allOutSchemeTypes, partnerType,fofoOrder.getCreateTimestamp(), false);for (InventoryItem inventoryItem : inventoryItems) {float itemCashback = 0;Set<Integer> schemeIds = new HashSet<>(schemeItemRepository.selectSchemeIdByItemId(inventoryItem.getItemId()));List<Scheme> itemActiveSchemes = allActiveSchemes.stream().filter(x -> schemeIds.contains(x.getId())).collect(Collectors.toList());for (Scheme scheme : itemActiveSchemes) {LOGGER.info("Scheme ==== {}", scheme);itemCashback += this.createSchemeInOut(scheme, inventoryItem);}LOGGER.info("itemCashback ==== {}", itemCashback);if (itemCashback > 0) {count++;totalCashback += itemCashback;}}if (count > 0) {walletService.addAmountToWallet(retailerId, fofoOrderId, WalletReferenceType.SCHEME_OUT, "Sales margin for invoice number "+ fofoOrder.getInvoiceNumber() + ". Total " + count + " pc(s)",totalCashback, fofoOrder.getCreateTimestamp());fofoOrder.setCashback(totalCashback);fofoOrderRepository.persist(fofoOrder);}}}@Overridepublic void rollbackSchemes(List<Integer> inventoryItemIds, int rollbackReference, String rollbackReason)throws Exception {Set<Integer> inventoryItemIdSet = new HashSet<>(inventoryItemIds);float amountToRollback = 0;List<SchemeInOut> schemes = schemeInOutRepository.selectByInventoryItemIds(inventoryItemIdSet);for (SchemeInOut schemeInOut : schemes) {if (schemeInOut.getRolledBackTimestamp() == null) {schemeInOut.setRolledBackTimestamp(LocalDateTime.now());if (schemeInOut.getStatus() == null || schemeInOut.getStatus().equals(SchemePayoutStatus.CREDITED)) {amountToRollback += schemeInOut.getAmount();}schemeInOut.setStatus(SchemePayoutStatus.REJECTED);schemeInOut.setStatusDescription(rollbackReason);}}if (amountToRollback > 0) {int inventoryItemId = inventoryItemIds.get(0);InventoryItem ii = inventoryItemRepository.selectById(inventoryItemId);Integer fofoId = ii.getFofoId();// Purchase p = purchaseRepository.selectById(ii.getPurchaseId());// TODO//walletService.rollbackAmountFromWallet(fofoId, amountToRollback, ii.getPurchaseId(),WalletReferenceType.SCHEME_IN, rollbackReason, LocalDateTime.now());}}@Overridepublic Map<String, Object> getSchemes(Set<Integer> roleIds, int offset, int limit)throws ProfitMandiBusinessException {Map<String, Object> map = new HashMap<>();List<Scheme> schemes = null;long size = 0;if (roleManager.isAdmin(roleIds)) {schemes = schemeRepository.selectAll(offset, limit);size = schemeRepository.selectAllCount();} else {schemes = schemeRepository.selectActiveAll(offset, limit);size = schemeRepository.selectAllActiveCount();}map.put("schemes", schemes);map.put("start", offset + 1);map.put("size", size);if (schemes.size() < limit) {map.put("end", offset + schemes.size());} else {map.put("end", offset + limit);}return map;}@Overridepublic List<Scheme> getPaginatedSchemes(Set<Integer> roleIds, int offset, int limit)throws ProfitMandiBusinessException {LOGGER.info("requested offset=[{}], limit = [{}]", offset, limit);List<Scheme> schemes = null;if (roleManager.isAdmin(roleIds)) {schemes = schemeRepository.selectAll(offset, limit);} else {schemes = schemeRepository.selectActiveAll(offset, limit);}return schemes;}@Override// This is being called to reverse schemes while processing price Droppublic void reverseSchemes(List<InventoryItem> inventoryItems, int priceDropId, String reversalReason)throws ProfitMandiBusinessException {PriceDrop priceDrop = priceDropRepository.selectById(priceDropId);Map<Integer, List<InventoryItem>> purchaseInventoryListMap = inventoryItems.stream().collect(Collectors.groupingBy(InventoryItem::getPurchaseId, Collectors.toList()));for (Map.Entry<Integer, List<InventoryItem>> purchaseEntry : purchaseInventoryListMap.entrySet()) {float amountToCredit = 0;float amountToDebit = 0;int purchaseId = purchaseEntry.getKey();List<InventoryItem> purchaseInventoryItemList = purchaseEntry.getValue();Map<Integer, InventoryItem> inventoryItemsMap = purchaseInventoryItemList.stream().collect(Collectors.toMap(x -> x.getId(), x -> x));List<SchemeInOut> schemeInOuts = schemeInOutRepository.selectByInventoryItemIds(inventoryItemsMap.keySet());LOGGER.info("Scheme InOuts , {}", schemeInOuts);if (schemeInOuts.size() == 0) {continue;}List<Integer> schemeIds = schemeInOuts.stream().map(x -> x.getSchemeId()).collect(Collectors.toList());Map<Integer, Scheme> schemesMap = schemeRepository.selectBySchemeIds(schemeIds, 0, schemeIds.size()).stream().collect(Collectors.toMap(x -> x.getId(), x -> x));for (SchemeInOut schemeInOut : schemeInOuts) {InventoryItem ii = inventoryItemsMap.get(schemeInOut.getInventoryItemId());Scheme scheme = schemesMap.get(schemeInOut.getSchemeId());if (scheme.getAmountType().equals(AmountType.FIXED)) {continue;}if (scheme.getType().equals(SchemeType.IN) && schemeInOut.getRolledBackTimestamp() == null) {float newAmount = getAmount(ii, scheme);if (schemeInOut.getAmount() - newAmount >= 0.01f) {schemeInOut.setRolledBackTimestamp(LocalDateTime.now());SchemeInOut sioNew = new SchemeInOut();sioNew.setAmount(newAmount);sioNew.setStatus(schemeInOut.getStatus());sioNew.setStatusDescription(schemeInOut.getStatusDescription());sioNew.setInventoryItemId(schemeInOut.getInventoryItemId());sioNew.setSchemeId(schemeInOut.getSchemeId());schemeInOutRepository.persist(sioNew);schemeInOut.setStatus(SchemePayoutStatus.REJECTED);schemeInOut.setStatusDescription("Pricedrop processed, new entries added");// IF not credited then dont consider any credit/debit for that sio entryif (schemeInOut.getCreditTimestamp() != null) {amountToCredit += sioNew.getAmount();amountToDebit += schemeInOut.getAmount();}}}}int fofoId = inventoryItems.get(0).getFofoId();if (amountToDebit > 0) {walletService.addAmountToWallet(fofoId, purchaseId, WalletReferenceType.SCHEME_IN,MessageFormat.format(reversalReason, purchaseInventoryItemList.size()), -amountToDebit,priceDrop.getAffectedOn());}if (amountToCredit > 0) {walletService.addAmountToWallet(fofoId, purchaseId, WalletReferenceType.SCHEME_IN,MessageFormat.format(reversalReason, purchaseInventoryItemList.size()), amountToCredit,priceDrop.getAffectedOn());}}}@Override// Always being called from cancel order/bad return means no SCHEME IN is consideredpublic void reverseSchemes(List<InventoryItem> inventoryItems, int reversalReference, String reversalReason,List<SchemeType> schemeTypes) throws ProfitMandiBusinessException {Map<Integer, InventoryItem> inventoryItemsMap = inventoryItems.stream().collect(Collectors.toMap(x -> x.getId(), x -> x));LOGGER.info("inventoryItems" + inventoryItems);List<SchemeInOut> schemeInOuts = schemeInOutRepository.selectByInventoryItemIds(inventoryItemsMap.keySet());LOGGER.info("schemeInOuts" + schemeInOuts);float amountToRollback = 0;if (!schemeInOuts.isEmpty()) {List<Integer> schemeIds = schemeInOuts.stream().map(x -> x.getSchemeId()).collect(Collectors.toList());LOGGER.info("schemeIds" + schemeIds);Map<Integer, Scheme> schemesMap = schemeRepository.selectBySchemeIds(schemeIds, 0, schemeIds.size()).stream().collect(Collectors.toMap(x -> x.getId(), x -> x));for (SchemeInOut schemeInOut : schemeInOuts) {Scheme scheme = schemesMap.get(schemeInOut.getSchemeId());if (schemeTypes.contains(scheme.getType())) {if (schemeInOut.getRolledBackTimestamp() == null) {schemeInOut.setRolledBackTimestamp(LocalDateTime.now());if (schemeInOut.getStatus().equals(SchemePayoutStatus.CREDITED)) {amountToRollback += schemeInOut.getAmount();}schemeInOut.setStatus(SchemePayoutStatus.REJECTED);schemeInOut.setStatusDescription(reversalReason);}}}}int fofoId = inventoryItems.get(0).getFofoId();WalletReferenceType walletReferenceType = schemeTypes.containsAll(SchemeService.OUT_SCHEME_TYPES)? WalletReferenceType.SCHEME_OUT: (schemeTypes.contains(SchemeType.ACTIVATION) ? WalletReferenceType.ACTIVATION_SCHEME: WalletReferenceType.INVESTMENT_PAYOUT);if (amountToRollback > 0) {// Mark appropriate reference of rollback investment marginif (schemeTypes.contains(SchemeType.INVESTMENT)) {reversalReference = Integer.parseInt(FormattingUtils.getYearMonth(schemeInOuts.get(0).getCreditTimestamp().minusMonths(1)));}walletService.rollbackAmountFromWallet(fofoId, amountToRollback, reversalReference, walletReferenceType,reversalReason, LocalDateTime.now());}}@Overridepublic double getTotalMargin(int itemId, PartnerType partnerType, LocalDateTime dateTime) {Session session = sessionFactory.getCurrentSession();CriteriaBuilder cb = session.getCriteriaBuilder();CriteriaQuery<Double> criteriaQuery = cb.createQuery(Double.class);Root<SchemeItem> schemeItem = criteriaQuery.from(SchemeItem.class);Root<Scheme> scheme = criteriaQuery.from(Scheme.class);Predicate schemePredicate = cb.equal(scheme.get(ProfitMandiConstants.AMOUNT_TYPE), AmountType.PERCENTAGE);Predicate lessThanPredicate = cb.lessThanOrEqualTo(scheme.get(ProfitMandiConstants.END_DATE_TIME), dateTime);Predicate greaterThanPredicate = cb.greaterThanOrEqualTo(scheme.get(ProfitMandiConstants.START_DATE_TIME),dateTime);Predicate joinPredicate = cb.equal(scheme.get("id"), schemeItem.get("schemeId"));Predicate schemeItemPredicate = cb.equal(schemeItem.get(ProfitMandiConstants.ITEM_ID), itemId);criteriaQuery.select(cb.sum(scheme.get(ProfitMandiConstants.AMOUNT))).where(schemePredicate, lessThanPredicate,greaterThanPredicate, schemeItemPredicate, joinPredicate);Query<Double> query = session.createQuery(criteriaQuery);return query.getSingleResult() + ProfitMandiConstants.SCHEME_INVESTMENT_MARGIN;}@Override@Cacheable(value = "itemSchemeCashback", cacheManager = "timeoutCacheManager")public Map<Integer, Float> getItemSchemeCashBack() {Map<Integer, Float> itemCashbackMap = new HashMap<>();Map<Integer, Scheme> cashbackSchemesMap = schemeRepository.selectActiveAll(Arrays.asList(SchemeType.ACTIVATION), PartnerType.ALL, LocalDateTime.now(), false).stream().filter(x -> x.getAmountType().equals(AmountType.FIXED)).collect(Collectors.toMap(x -> x.getId(), x -> x));if (cashbackSchemesMap.size() > 0) {List<SchemeItem> schemeItems = schemeItemRepository.selectBySchemeIds(cashbackSchemesMap.keySet());schemeItems.stream().forEach(x -> {float cashbackAmount = cashbackSchemesMap.get(x.getSchemeId()).getAmount();if (!itemCashbackMap.containsKey(x.getItemId())) {itemCashbackMap.put(x.getItemId(), cashbackAmount);} else {itemCashbackMap.put(x.getItemId(), itemCashbackMap.get(x.getItemId()) + cashbackAmount);}});}// A107FD Model needs to removeditemCashbackMap.remove(30211);itemCashbackMap.remove(30212);itemCashbackMap.remove(30213);itemCashbackMap.remove(30756);return itemCashbackMap;}/** @Override public void updateSchmesForModel(int catalogId) throws* ProfitMandiBusinessException { List<Item> items =* itemRepository.selectAllByCatalogItemId(catalogId); Map<Integer, Scheme>* schemes = schemeRepository .selectAllByItemIds(items.stream().map(x ->* x.getId()).collect(Collectors.toList()));** }*/@Overridepublic List<Scheme> selectSchemeByPartnerType(PartnerType partnerType, LocalDate onDate, int itemId,boolean isAdmin, int offset, int limit) throws ProfitMandiBusinessException {Session session = sessionFactory.getCurrentSession();CriteriaBuilder cb = session.getCriteriaBuilder();CriteriaQuery<Scheme> query = cb.createQuery(Scheme.class);Root<Scheme> scheme = query.from(Scheme.class);List<PartnerType> pt = new ArrayList<>();pt.add(PartnerType.ALL);pt.add(partnerType);Predicate p1 = cb.in(scheme.get("partnerType")).value(pt);Predicate p2 = cb.isNotNull(scheme.get("activeTimestamp"));cb.desc(cb.isNull(scheme.get("expireTimestamp")));Predicate p3 = null;Predicate finalPredicate = null;if (itemId != 0) {List<Integer> schemeIds = schemeItemRepository.selectSchemeIdByItemId(itemId);LOGGER.info("schemeId" + schemeIds);if (schemeIds.isEmpty()) {return new ArrayList<>();}p3 = cb.in(scheme.get("id")).value(schemeIds);if (!isAdmin) {finalPredicate = cb.and(p1, p2, p3, cb.greaterThan(scheme.get("endDateTime"), onDate.atStartOfDay()),cb.lessThanOrEqualTo(scheme.get("startDateTime"), onDate.atStartOfDay()));query.where(finalPredicate);} else {finalPredicate = cb.and(p1, p3);query.where(finalPredicate);}} else {if (!isAdmin) {finalPredicate = cb.and(p1, p2);query.where(finalPredicate);} else {query.where(p1);}}query.orderBy(cb.desc(cb.function("isnull", Boolean.class, scheme.get("expireTimestamp"))));return session.createQuery(query).setFirstResult(offset).setMaxResults(limit).getResultList();}@Overridepublic long selectSchemeCount(PartnerType partnerType, LocalDate onDate, int itemId, boolean isAdmin) {Session session = sessionFactory.getCurrentSession();CriteriaBuilder cb = session.getCriteriaBuilder();CriteriaQuery<Long> query = cb.createQuery(Long.class);Root<Scheme> scheme = query.from(Scheme.class);List<PartnerType> pt = new ArrayList<>();pt.add(PartnerType.ALL);pt.add(partnerType);Predicate p1 = cb.in(scheme.get("partnerType")).value(pt);Predicate p2 = cb.isNotNull(scheme.get("activeTimestamp"));Predicate finalPredicate = null;if (itemId != 0) {List<Integer> schemeIds = schemeItemRepository.selectSchemeIdByItemId(itemId);Predicate p3 = cb.in(scheme.get("id")).value(schemeIds);if (!isAdmin) {finalPredicate = cb.and(p1, p2, p3, cb.greaterThan(scheme.get("endDateTime"), onDate.atStartOfDay()),cb.lessThanOrEqualTo(scheme.get("startDateTime"), onDate.atStartOfDay()));query.select(cb.count(scheme)).where(finalPredicate);} else {finalPredicate = cb.and(p1, p3);query.select(cb.count(scheme)).where(finalPredicate);}} else {if (!isAdmin) {finalPredicate = cb.and(p1, p2);query.select(cb.count(scheme)).where(finalPredicate);} else {query.select(cb.count(scheme)).where(p1);}}return session.createQuery(query).getSingleResult();}@Overridepublic void processActivation() throws ProfitMandiBusinessException {List<SchemeInOut> pendingPayouts = schemeInOutRepository.selectAllPending();List<Integer> schemeIds = new ArrayList<>();Set<Integer> inventoryIds = new HashSet<>();for (SchemeInOut pendingPayout : pendingPayouts) {schemeIds.add(pendingPayout.getSchemeId());}Map<Integer, Scheme> schemesMap = schemeRepository.selectBySchemeIds(schemeIds, 0, 0).stream().filter(x -> x.getType().equals(SchemeType.ACTIVATION)).collect(Collectors.toMap(x -> x.getId(), x -> x));pendingPayouts = pendingPayouts.stream().filter(x -> schemesMap.get(x.getSchemeId()) != null).collect(Collectors.toList());for (SchemeInOut pendingPayout : pendingPayouts) {inventoryIds.add(pendingPayout.getInventoryItemId());}Map<Integer, InventoryItem> inventoryItemMap = inventoryItemRepository.selectByIds(inventoryIds).stream().collect(Collectors.toMap(x -> x.getId(), x -> x));Map<String, InventoryItem> serialNumberMap = inventoryItemMap.values().stream().collect(Collectors.toMap(x -> x.getSerialNumber(), x -> x));List<ActivatedImei> activatedImeis = activatedImeiRepository.selectBySerialNumbers(new ArrayList<>(serialNumberMap.keySet()));Map<String, ActivatedImei> activatedImeiMap = activatedImeis.stream().collect(Collectors.toMap(x -> x.getSerialNumber(), x -> x));for (SchemeInOut pendingPayout : pendingPayouts) {InventoryItem ii = inventoryItemMap.get(pendingPayout.getInventoryItemId());String serialNumber = ii.getSerialNumber();ActivatedImei activatedImei = activatedImeiMap.get(serialNumber);if (activatedImei == null) {continue;}Scheme scheme = schemesMap.get(pendingPayout.getSchemeId());if (activatedImei.getActivationTimestamp().isBefore(scheme.getEndDateTime())&& activatedImei.getActivationTimestamp().isAfter(scheme.getStartDateTime())) {int fofoId = ii.getFofoId();// Get latest order Idint orderId = scanRecordRepository.selectByInventoryItemId(ii.getId()).stream().filter(x -> x.getOrderId() > 0).sorted(Comparator.comparing(ScanRecord::getCreateTimestamp).reversed()).findFirst().get().getOrderId();FofoOrder fofoOrder = fofoOrderRepository.selectByOrderId(orderId);walletService.addAmountToWallet(fofoId, orderId, WalletReferenceType.ACTIVATION_SCHEME,"Activation margin for Imei#" + serialNumber, pendingPayout.getAmount(),fofoOrder.getCreateTimestamp());pendingPayout.setCreditTimestamp(LocalDateTime.now());pendingPayout.setStatus(SchemePayoutStatus.CREDITED);pendingPayout.setStatusDescription("Activation margin credited");} else {pendingPayout.setStatus(SchemePayoutStatus.REJECTED);pendingPayout.setRolledBackTimestamp(LocalDateTime.now());;pendingPayout.setStatusDescription("Rejected, activated on " + FormattingUtils.formatDate(activatedImei.getActivationTimestamp()));}}}}