Rev 35458 | Blame | Compare with Previous | Last modification | View Log | RSS feed
package com.spice.profitmandi.dao.service;import com.spice.profitmandi.common.exception.ProfitMandiBusinessException;import com.spice.profitmandi.common.model.CustomPaymentOption;import com.spice.profitmandi.dao.entity.catalog.Item;import com.spice.profitmandi.dao.entity.dtr.ScratchOffer;import com.spice.profitmandi.dao.entity.fofo.FofoOrder;import com.spice.profitmandi.dao.entity.fofo.FofoOrderItem;import com.spice.profitmandi.dao.entity.scratch.GiftEntity;import com.spice.profitmandi.dao.entity.scratch.OfferEntity;import com.spice.profitmandi.dao.entity.scratch.ScratchRequest;import com.spice.profitmandi.dao.repository.catalog.ItemRepository;import com.spice.profitmandi.dao.repository.dtr.ScratchOfferRepository;import com.spice.profitmandi.dao.repository.fofo.FofoOrderItemRepository;import com.spice.profitmandi.dao.repository.fofo.FofoOrderRepository;import com.spice.profitmandi.dao.repository.scratch.GiftRepository;import com.spice.profitmandi.dao.repository.scratch.SeasonalOfferRepository;import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import java.time.LocalDate;import java.time.LocalDateTime;import java.time.LocalTime;import java.util.*;import java.util.function.Function;import java.util.stream.Collectors;@Servicepublic class ScratchService {private static final Logger logger = LogManager.getLogger(ScratchService.class);@AutowiredSeasonalOfferRepository seasonalOfferRepository;@AutowiredGiftRepository giftRepository;@AutowiredScratchOfferRepository scratchOfferRepository;@AutowiredFofoOrderItemRepository fofoOrderItemRepository;@AutowiredItemRepository itemRepository;@AutowiredFofoOrderRepository fofoOrderRepository;public void processScratchOffer(int fofoOrderId, Set<CustomPaymentOption> paymentOptions, Set<Integer> fofoOrderItemIds) throws ProfitMandiBusinessException {List<OfferEntity> activeOffers = seasonalOfferRepository.getOffersByDate(LocalDate.now());if (activeOffers.isEmpty()) {return;}FofoOrder fofoOrder = fofoOrderRepository.selectByOrderId(fofoOrderId);OfferEntity eligibleOffer = findEligibleOffer(activeOffers, fofoOrder);if (eligibleOffer == null) {logger.info("No eligible offer for order {}", fofoOrderId);return;}ScratchOffer availedOffer = scratchOfferRepository.getScractchOfferByCustomerIdAndOfferId(fofoOrder.getCustomerId(), eligibleOffer.getId());if (availedOffer != null) {logger.info("Customer {} already availed offer {}", fofoOrder.getCustomerId(), eligibleOffer.getId());return;}this.processOffer(eligibleOffer, fofoOrder);}private OfferEntity findEligibleOffer(List<OfferEntity> activeOffers, FofoOrder fofoOrder) {int customerFofoId = fofoOrder.getFofoId();// Check PartnerWise offers firstfor (OfferEntity activeOffer : activeOffers) {if (!"PartnerWise".equals(activeOffer.getClassification())) {continue;}List<GiftEntity> gifts = giftRepository.findByOfferId(activeOffer.getId());for (GiftEntity gift : gifts) {if (gift.getFofoStore() == null || gift.getFofoStore().trim().isEmpty()) {continue;}boolean matches = Arrays.stream(gift.getFofoStore().split(",")).map(String::trim).filter(s -> !s.isEmpty()).anyMatch(store -> {try {return Integer.parseInt(store) == customerFofoId;} catch (NumberFormatException e) {return false;}});if (matches) {return activeOffer;}}}// Fallback to first non-PartnerWise offerreturn activeOffers.stream().filter(offer -> !"PartnerWise".equals(offer.getClassification())).findFirst().orElse(null);}private boolean checkGiftAvailability(LocalDate date, int perDayMaxQty, OfferEntity offer) {GiftEntity defaultGift = giftRepository.getDefaultGift(offer.getId());if (defaultGift == null) return false;Integer giftCounts = scratchOfferRepository.countTodaysGiftDistribution(date.atStartOfDay(), date.atTime(LocalTime.MAX), defaultGift.getId());return giftCounts < perDayMaxQty;}private boolean isAppleItem(FofoOrder fofoOrder) {List<FofoOrderItem> fofoOrderItems = fofoOrderItemRepository.selectByOrderId(fofoOrder.getId());if (fofoOrderItems == null || fofoOrderItems.isEmpty()) {return false;}return fofoOrderItems.stream().anyMatch(item -> item != null && "apple".equalsIgnoreCase(item.getBrand()));}private boolean processOffer(OfferEntity offer, FofoOrder fofoOrder) {logger.info("Processing offer {} for order {}", offer.getId(), fofoOrder.getId());List<GiftEntity> allGifts = giftRepository.findNonDefaultGIft(offer.getId());GiftEntity defaultGift = giftRepository.getDefaultGift(offer.getId());if (allGifts.isEmpty()) {logger.warn("Offer {} has no gifts", offer.getId());return false;}// Apple items always get the last giftif (isAppleItem(fofoOrder)) {GiftEntity lastGift = allGifts.get(allGifts.size() - 1);if (lastGift.getMaxRedemptions() > 0) {createScratchOffer(fofoOrder, offer, lastGift);} else {createBetterLuckNextTimeScratch(fofoOrder, offer);}return true;}// Check daily limitif (!checkGiftAvailability(LocalDate.now(), offer.getUserLimit(), offer)) {createDefaultGiftScratch(fofoOrder, offer, defaultGift);return true;}// Find eligible gifts by cart value and categoryList<FofoOrderItem> orderItems = fofoOrderItemRepository.selectByOrderId(fofoOrder.getId());Set<Integer> itemCategoryIds = new HashSet<>();for (FofoOrderItem orderItem : orderItems) {try {Item item = itemRepository.selectById(orderItem.getItemId());if (item != null) {itemCategoryIds.add(item.getCategoryId());}} catch (ProfitMandiBusinessException e) {logger.warn("Item {} not found", orderItem.getItemId());}}float totalAmount = fofoOrder.getTotalAmount();List<GiftEntity> allOfferGifts = giftRepository.findByOfferId(offer.getId());List<GiftEntity> eligibleGifts = allOfferGifts.stream().filter(gift -> gift.getMaxRedemptions() > 0&& totalAmount >= gift.getMinCartValue()&& totalAmount <= gift.getMaxCartValue()&& itemCategoryIds.stream().anyMatch(catId -> isItemCategoryEligible(gift.getProductCategory(), catId))).collect(Collectors.toList());if (eligibleGifts.isEmpty()) {createDefaultGiftScratch(fofoOrder, offer, defaultGift);return true;}GiftEntity selectedGift = selectGiftByClassification(offer, eligibleGifts, fofoOrder);if (selectedGift == null || selectedGift.getMaxRedemptions() <= 0) {createDefaultGiftScratch(fofoOrder, offer, defaultGift);return true;}createScratchOffer(fofoOrder, offer, selectedGift);return true;}private boolean isItemCategoryEligible(String giftCategories, Integer itemCategoryId) {if (giftCategories == null || giftCategories.trim().isEmpty()) {return false;}return Arrays.stream(giftCategories.split(",")).map(String::trim).filter(s -> !s.isEmpty()).map(category -> {try {return Integer.parseInt(category);} catch (NumberFormatException e) {return -1;}}).anyMatch(itemCategoryId::equals);}private GiftEntity selectGiftByClassification(OfferEntity offer, List<GiftEntity> eligibleGifts, FofoOrder fofoOrder) {switch (offer.getClassification()) {case "Serial":return eligibleGifts.get(0);case "Random":List<GiftEntity> shuffled = new ArrayList<>(eligibleGifts);Collections.shuffle(shuffled);return shuffled.get(0);case "PartnerWise":int fofoId = fofoOrder.getFofoId();return eligibleGifts.stream().filter(gift -> gift.getFofoStore() != null&& Arrays.stream(gift.getFofoStore().split(",")).map(String::trim).anyMatch(s -> {try { return Integer.parseInt(s) == fofoId; }catch (NumberFormatException e) { return false; }})).findFirst().orElse(null);default:logger.warn("Unknown classification: {}", offer.getClassification());return null;}}public void createBetterLuckNextTimeScratch(FofoOrder order, OfferEntity offer) {ScratchOffer so = new ScratchOffer();so.setCustomerId(order.getCustomerId());so.setOfferId(offer.getId());so.setGiftId(1);so.setInvoiceNumber(order.getInvoiceNumber());so.setCreatedTimestamp(LocalDateTime.now());so.setOfferName(offer.getName());scratchOfferRepository.persist(so);}public void createScratchOffer(FofoOrder order, OfferEntity offer, GiftEntity gift) {int updated = giftRepository.decrementMaxRedemptions(gift.getId());if (updated == 0) {logger.warn("Gift {} has no remaining redemptions", gift.getId());return;}ScratchOffer so = new ScratchOffer();so.setCustomerId(order.getCustomerId());so.setOfferId(offer.getId());so.setGiftId(gift.getId());so.setInvoiceNumber(order.getInvoiceNumber());so.setCreatedTimestamp(LocalDateTime.now());so.setOfferName(gift.getName());scratchOfferRepository.persist(so);logger.info("Created scratch offer for order {} gift {}", order.getId(), gift.getId());}public void createDefaultGiftScratch(FofoOrder order, OfferEntity offer, GiftEntity gift) {ScratchOffer so = new ScratchOffer();so.setCustomerId(order.getCustomerId());so.setOfferId(offer.getId());so.setGiftId(gift.getId());so.setInvoiceNumber(order.getInvoiceNumber());so.setCreatedTimestamp(LocalDateTime.now());so.setOfferName(gift.getName());scratchOfferRepository.persist(so);}public boolean createOffer(ScratchRequest request) {OfferEntity offer = mapToOfferEntity(request);seasonalOfferRepository.save(offer);List<GiftEntity> gifts = mapToGiftEntities(request.getGifts(), offer.getId());gifts.forEach(giftRepository::save);return offer.getId() > 0 && giftRepository.findByOfferId(offer.getId()).size() == request.getGifts().size();}public boolean updateOffer(Integer offerId, ScratchRequest request) {OfferEntity existingOffer = seasonalOfferRepository.findById(offerId);boolean res = false;if (existingOffer != null) {updateOfferEntity(existingOffer, request);updateGifts(existingOffer.getId(), request.getGifts());res = true;}return res;}//update offerprivate void updateOfferEntity(OfferEntity existingOffer, ScratchRequest request) {existingOffer.setName(request.getName());existingOffer.setDescription(request.getDescription());existingOffer.setStartDate(request.getStartDate());existingOffer.setEndDate(request.getEndDate());existingOffer.setTermsCondition(request.getTermsCondition());existingOffer.setUserLimit(request.getUserLimit());existingOffer.setScratchValidity(request.getScratchValidity());existingOffer.setProductCategory(request.getProductCategory());existingOffer.setPaymentMethod(request.getPaymentMethod());existingOffer.setClassification(request.getClassification());}//update giftprivate void updateGifts(Integer offerId, List<ScratchRequest.GiftData> giftsData) {Map<Integer, GiftEntity> existingGifts = giftRepository.findByOfferId(offerId).stream().collect(Collectors.toMap(GiftEntity::getId, Function.identity()));for (ScratchRequest.GiftData giftData : giftsData) {if (giftData.getId() != null && existingGifts.containsKey(giftData.getId())) {GiftEntity existingGift = existingGifts.get(giftData.getId());updateGiftEntity(existingGift, giftData);existingGifts.remove(giftData.getId());} else {GiftEntity gift = new GiftEntity();gift.setName(giftData.getName());gift.setThumbnailUrl(giftData.getThumbnailUrl());gift.setMinCartValue(giftData.getMinCartValue());gift.setMaxRedemptions(giftData.getMaxRedemptions());gift.setOfferId(offerId);gift.setMaxCartValue(giftData.getMaxCartValue());gift.setFofoStore(giftData.getFofoStore());gift.setProductCategory(giftData.getProductCategory());gift.setIsDefault(giftData.isDefault());giftRepository.save(gift);}}}private void updateGiftEntity(GiftEntity gift, ScratchRequest.GiftData data) {gift.setName(data.getName());gift.setThumbnailUrl(data.getThumbnailUrl());gift.setMinCartValue(data.getMinCartValue());gift.setMaxRedemptions(data.getMaxRedemptions());gift.setMaxCartValue(data.getMaxCartValue());gift.setFofoStore(data.getFofoStore());gift.setProductCategory(data.getProductCategory());gift.setIsDefault(data.isDefault());}//offerprivate OfferEntity mapToOfferEntity(ScratchRequest request) {OfferEntity offer = new OfferEntity();offer.setName(request.getName());offer.setDescription(request.getDescription());offer.setOfferImage(request.getOfferImage());offer.setOfferType(request.getOfferType());offer.setStartDate(request.getStartDate());offer.setEndDate(request.getEndDate());offer.setTermsCondition(request.getTermsCondition());offer.setUserLimit(request.getUserLimit());offer.setScratchValidity(request.getScratchValidity());offer.setProductCategory(request.getProductCategory());offer.setPaymentMethod(request.getPaymentMethod());offer.setClassification(request.getClassification());logger.info("active flag - " + request.isActive());offer.setActive(request.isActive());return offer;}//giftprivate List<GiftEntity> mapToGiftEntities(List<ScratchRequest.GiftData> giftsData, Integer offerId) {return giftsData.stream().map(giftData -> {logger.info("giftData: {}", giftData);GiftEntity gift = new GiftEntity();gift.setName(giftData.getName());gift.setThumbnailUrl(giftData.getThumbnailUrl());gift.setMinCartValue(giftData.getMinCartValue());gift.setMaxRedemptions(giftData.getMaxRedemptions());gift.setOfferId(offerId);gift.setMaxCartValue(giftData.getMaxCartValue());gift.setFofoStore(giftData.getFofoStore());gift.setProductCategory(giftData.getProductCategory());gift.setIsDefault(giftData.isDefault());return gift;}).collect(Collectors.toList());}}