Blame | Last modification | View Log | RSS feed
package com.spice.profitmandi.web.service;import com.fasterxml.jackson.databind.ObjectMapper;import com.spice.profitmandi.dao.entity.catalog.Item;import com.spice.profitmandi.dao.entity.dtr.WebOffer;import com.spice.profitmandi.dao.entity.dtr.WebOfferProduct;import com.spice.profitmandi.dao.repository.catalog.ItemRepository;import com.spice.profitmandi.dao.repository.dtr.WebOfferProductRepository;import com.spice.profitmandi.dao.repository.dtr.WebOfferRepository;import com.spice.profitmandi.web.model.EmiOfferImportDTO;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.io.InputStream;import java.time.LocalDateTime;import java.util.*;import java.util.stream.Collectors;/*** Imports EMI scraper JSON (one JSON per scrape run) and creates one* dtr.web_offer per (product × bank), with a dtr.web_offer_product row linking* the catalog_id. Plan details are summarised into detailedText.* <p>* SKU resolution: catalog.item.brand_identifier -> catalog.item.catalog_item_id* which is the WebOfferProduct.entityId.*/@Servicepublic class EmiOfferImportService {private static final Logger LOGGER = LogManager.getLogger(EmiOfferImportService.class);@Autowiredprivate ItemRepository itemRepository;@Autowiredprivate WebOfferRepository webOfferRepository;@Autowiredprivate WebOfferProductRepository webOfferProductRepository;public ImportResult importFromJson(InputStream in, LocalDateTime startDate, LocalDateTime endDate, boolean dryRun)throws Exception {ObjectMapper mapper = new ObjectMapper();EmiOfferImportDTO dto = mapper.readValue(in, EmiOfferImportDTO.class);ImportResult result = new ImportResult();result.dryRun = dryRun;result.generatedAt = dto.getGeneratedAt();if (dto.getProducts() == null || dto.getProducts().isEmpty()) {return result;}List<String> skus = dto.getProducts().stream().map(EmiOfferImportDTO.Product::getSku).filter(s -> s != null && !s.isEmpty()).distinct().collect(Collectors.toList());Map<String, Integer> skuToCatalogId = resolveSkus(skus, result);for (EmiOfferImportDTO.Product product : dto.getProducts()) {Integer catalogId = skuToCatalogId.get(product.getSku());if (catalogId == null) {continue; // already recorded in missingSkus}if (product.getCardTypes() == null) continue;for (EmiOfferImportDTO.CardType cardType : product.getCardTypes()) {if (cardType.getBanks() == null) continue;for (EmiOfferImportDTO.Bank bank : cardType.getBanks()) {if (bank.getPlans() == null || bank.getPlans().isEmpty()) {result.banksSkippedNoPlans++;continue;}createOffer(product, cardType, bank, catalogId, startDate, endDate, dryRun, result);}}}return result;}private Map<String, Integer> resolveSkus(List<String> skus, ImportResult result) {Map<String, Integer> out = new HashMap<>();if (skus.isEmpty()) return out;LOGGER.info("EmiImport: resolving {} sku(s): {}", skus.size(), skus);List<Item> items = itemRepository.selectAllByBrandIdentifiers(skus);LOGGER.info("EmiImport: itemRepository returned {} row(s) for {} sku(s)", items.size(), skus.size());Set<String> matched = new HashSet<>();for (Item item : items) {String sku = item.getBrandIdentifier();LOGGER.info("EmiImport: matched item id={} brandIdentifier='{}' catalogItemId={}",item.getId(), sku, item.getCatalogItemId());if (sku == null) continue;matched.add(sku);// keep first occurrence; catalog_item_id should be identical across colors of same catalogout.putIfAbsent(sku, item.getCatalogItemId());}for (String sku : skus) {if (!matched.contains(sku)) {LOGGER.warn("EmiImport: NO match for sku '{}' (len={})", sku, sku == null ? -1 : sku.length());result.missingSkus.add(sku);}}return out;}private void createOffer(EmiOfferImportDTO.Product product, EmiOfferImportDTO.CardType cardType,EmiOfferImportDTO.Bank bank, int catalogId, LocalDateTime startDate, LocalDateTime endDate,boolean dryRun, ImportResult result) {String title = bank.getBankName();String smallText = inferOfferTypeSummary(bank.getPlans());String detailedText = buildDetailedText(product, bank);OfferPreview preview = new OfferPreview();preview.sku = product.getSku();preview.catalogId = catalogId;preview.title = title;preview.smallText = smallText;preview.detailedText = detailedText;preview.planCount = bank.getPlans().size();result.previews.add(preview);if (dryRun) {result.offersWouldCreate++;return;}WebOffer offer = new WebOffer();offer.setTitle(title);offer.setSmallText(smallText);offer.setDetailedText(detailedText);offer.setStartDate(startDate);offer.setEndDate(endDate);offer.setActive(true);offer.setCreatedDate(LocalDateTime.now());webOfferRepository.persist(offer);WebOfferProduct wop = new WebOfferProduct();wop.setWebOfferId(offer.getId());wop.setEntityId(catalogId);wop.setRank(0);boolean exists = webOfferProductRepository.isExists(wop.getWebOfferId(), wop.getEntityId());if (!exists) {webOfferProductRepository.persist(wop);}preview.webOfferId = offer.getId();result.offersCreated++;result.productsLinked++;LOGGER.info("EmiImport: created web_offer id={} title='{}' catalogId={}", offer.getId(), title, catalogId);}private String inferOfferTypeSummary(List<EmiOfferImportDTO.Plan> plans) {Map<String, Integer> counts = new LinkedHashMap<>();for (EmiOfferImportDTO.Plan p : plans) {String ot = p.getOfferType();if (ot == null || ot.isEmpty()) continue;counts.merge(ot, 1, Integer::sum);}if (counts.isEmpty()) return "EMI";return counts.keySet().iterator().next(); // dominant/first offer type}private String buildDetailedText(EmiOfferImportDTO.Product product, EmiOfferImportDTO.Bank bank) {StringBuilder sb = new StringBuilder();sb.append(product.getProductName()).append(" · ").append(product.getPrice()).append("\n");for (EmiOfferImportDTO.Plan p : bank.getPlans()) {sb.append(nz(p.getTenure())).append(" ");sb.append(nz(p.getEmiAmount()));if (p.getOfferType() != null && !p.getOfferType().isEmpty()) {sb.append(" ").append(p.getOfferType());}if (p.getTotalCost() != null && !p.getTotalCost().isEmpty()) {sb.append(" total ").append(p.getTotalCost());}if (p.getInterestRate() != null && !p.getInterestRate().isEmpty()) {sb.append(" @").append(p.getInterestRate());}if (p.getDiscount() != null && !p.getDiscount().isEmpty()) {sb.append(" disc ").append(p.getDiscount());}sb.append("\n");}return sb.toString().trim();}private String nz(String s) {return s == null ? "" : s;}public static class ImportResult {public boolean dryRun;public String generatedAt;public int offersCreated;public int offersWouldCreate;public int productsLinked;public int banksSkippedNoPlans;public List<String> missingSkus = new ArrayList<>();public List<OfferPreview> previews = new ArrayList<>();}public static class OfferPreview {public String sku;public int catalogId;public int webOfferId; // 0 when dry-runpublic String title;public String smallText;public String detailedText;public int planCount;}}