Subversion Repositories SmartDukaan

Rev

Rev 37840 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
27877 amit.gupta 1
package com.spice.profitmandi.service.offers;
2
 
37845 amit 3
import com.spice.profitmandi.service.warehouse.BillingWarehouseService;
4
 
29783 amit.gupta 5
import com.google.common.collect.Lists;
27877 amit.gupta 6
import com.google.gson.Gson;
7
import com.spice.profitmandi.common.exception.ProfitMandiBusinessException;
33030 amit.gupta 8
import com.spice.profitmandi.common.model.CustomRetailer;
29683 amit.gupta 9
import com.spice.profitmandi.common.model.PartnerTargetModel;
10
import com.spice.profitmandi.common.model.ProfitMandiConstants;
33999 tejus.loha 11
import com.spice.profitmandi.common.util.FileUtil;
35205 amit 12
import com.spice.profitmandi.common.util.FormattingUtils;
31920 amit.gupta 13
import com.spice.profitmandi.common.util.Utils;
27877 amit.gupta 14
import com.spice.profitmandi.dao.entity.catalog.ItemCriteria;
15
import com.spice.profitmandi.dao.entity.catalog.Offer;
29783 amit.gupta 16
import com.spice.profitmandi.dao.entity.catalog.TagListing;
31903 amit.gupta 17
import com.spice.profitmandi.dao.entity.catalog.TargetSlabEntity;
31920 amit.gupta 18
import com.spice.profitmandi.dao.entity.fofo.FofoLineItem;
19
import com.spice.profitmandi.dao.entity.fofo.FofoOrderItem;
31205 amit.gupta 20
import com.spice.profitmandi.dao.entity.fofo.InventoryItem;
21
import com.spice.profitmandi.dao.entity.fofo.OfferPayout;
31920 amit.gupta 22
import com.spice.profitmandi.dao.entity.transaction.LineItem;
23
import com.spice.profitmandi.dao.entity.transaction.Order;
31747 amit.gupta 24
import com.spice.profitmandi.dao.entity.transaction.UserWalletHistory;
31920 amit.gupta 25
import com.spice.profitmandi.dao.entity.warehouse.WarehouseInventoryItem;
26
import com.spice.profitmandi.dao.entity.warehouse.WarehouseScan;
27
import com.spice.profitmandi.dao.enumuration.catalog.AchievementType;
29783 amit.gupta 28
import com.spice.profitmandi.dao.enumuration.catalog.AmountType;
29499 amit.gupta 29
import com.spice.profitmandi.dao.enumuration.catalog.OfferSchemeType;
31205 amit.gupta 30
import com.spice.profitmandi.dao.enumuration.transaction.SchemePayoutStatus;
35394 amit 31
import com.spice.profitmandi.dao.model.*;
35856 amit 32
import com.spice.profitmandi.dao.repository.GenericRepository;
30066 amit.gupta 33
import com.spice.profitmandi.dao.repository.catalog.*;
35205 amit 34
import com.spice.profitmandi.dao.repository.dtr.FofoStoreRepository;
31920 amit.gupta 35
import com.spice.profitmandi.dao.repository.fofo.ActivatedImeiRepository;
36
import com.spice.profitmandi.dao.repository.fofo.InventoryItemRepository;
31205 amit.gupta 37
import com.spice.profitmandi.dao.repository.fofo.OfferPayoutRepository;
31920 amit.gupta 38
import com.spice.profitmandi.dao.repository.transaction.LineItemImeisRepository;
33087 amit.gupta 39
import com.spice.profitmandi.dao.repository.warehouse.AgeingSummaryModel;
31920 amit.gupta 40
import com.spice.profitmandi.dao.repository.warehouse.WarehouseInventoryItemRepository;
41
import com.spice.profitmandi.dao.repository.warehouse.WarehouseScanRepository;
35205 amit 42
import com.spice.profitmandi.service.NotificationService;
31920 amit.gupta 43
import com.spice.profitmandi.service.pricecircular.PriceCircularService;
44
import com.spice.profitmandi.service.scheme.InventoryPayoutModel;
27877 amit.gupta 45
import com.spice.profitmandi.service.user.RetailerService;
31205 amit.gupta 46
import com.spice.profitmandi.service.wallet.WalletService;
35205 amit 47
import com.spice.profitmandi.service.whatsapp.WhatsappMessageType;
31205 amit.gupta 48
import in.shop2020.model.v1.order.WalletReferenceType;
33999 tejus.loha 49
import org.apache.commons.io.output.ByteArrayOutputStream;
30066 amit.gupta 50
import org.apache.logging.log4j.LogManager;
51
import org.apache.logging.log4j.Logger;
52
import org.apache.poi.ss.usermodel.Cell;
53
import org.apache.poi.ss.usermodel.CellType;
54
import org.apache.poi.ss.usermodel.Row;
55
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
56
import org.apache.poi.xssf.usermodel.XSSFRow;
57
import org.apache.poi.xssf.usermodel.XSSFSheet;
58
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
59
import org.springframework.beans.factory.annotation.Autowired;
60
import org.springframework.cache.CacheManager;
61
import org.springframework.cache.annotation.Cacheable;
36633 amit 62
import org.springframework.transaction.annotation.Propagation;
36305 amit 63
import org.springframework.transaction.annotation.Transactional;
30066 amit.gupta 64
import org.springframework.stereotype.Component;
27877 amit.gupta 65
 
30066 amit.gupta 66
import java.io.IOException;
67
import java.io.InputStream;
68
import java.time.LocalDate;
31205 amit.gupta 69
import java.time.LocalDateTime;
30066 amit.gupta 70
import java.time.YearMonth;
71
import java.util.*;
72
import java.util.stream.Collectors;
73
 
27877 amit.gupta 74
@Component
75
public class OfferServiceImpl implements OfferService {
76
 
37845 amit 77
    @Autowired
78
    private BillingWarehouseService billingWarehouseService;
79
 
80
 
35394 amit 81
    private static final Logger LOGGER = LogManager.getLogger(OfferServiceImpl.class);
29499 amit.gupta 82
 
35394 amit 83
    // Constants
84
    private static final List<String> TARGETS = Arrays.asList("Target 1", "Target 2", "Target 3", "Target 4", "Target 5");
85
    private static final int STOCK_AGEING_THRESHOLD_DAYS = 300;
86
 
87
    // Dependencies - Core
31747 amit.gupta 88
    @Autowired
89
    private Gson gson;
27877 amit.gupta 90
 
31747 amit.gupta 91
    @Autowired
36049 amit 92
    private OfferService offerServiceProxy; // self-injection for Spring cache proxy
35205 amit 93
 
36049 amit 94
    @Autowired
95
    private CacheManager redisCacheManager;
96
 
97
    @Autowired
98
    private CacheManager redisShortCacheManager;
99
 
35394 amit 100
    // Dependencies - Repositories
35205 amit 101
    @Autowired
35856 amit 102
    private GenericRepository genericRepository;
103
 
104
    @Autowired
31747 amit.gupta 105
    private OfferRepository offerRepository;
27877 amit.gupta 106
 
31747 amit.gupta 107
    @Autowired
35394 amit 108
    private OfferPayoutRepository offerPayoutRepository;
27877 amit.gupta 109
 
31747 amit.gupta 110
    @Autowired
35394 amit 111
    private OfferTargetSlabRepository offerTargetSlabRepository;
31205 amit.gupta 112
 
31747 amit.gupta 113
    @Autowired
114
    private ItemCriteriaRepository itemCriteriaRepository;
27877 amit.gupta 115
 
31747 amit.gupta 116
    @Autowired
117
    private ItemRepository itemRepository;
27877 amit.gupta 118
 
31747 amit.gupta 119
    @Autowired
120
    private TagListingRepository tagListingRepository;
29783 amit.gupta 121
 
31747 amit.gupta 122
    @Autowired
35205 amit 123
    private FofoStoreRepository fofoStoreRepository;
30684 amit.gupta 124
 
31747 amit.gupta 125
    @Autowired
35394 amit 126
    private ActivatedImeiRepository activatedImeiRepository;
27877 amit.gupta 127
 
31920 amit.gupta 128
    @Autowired
129
    private WarehouseScanRepository warehouseScanRepository;
130
 
131
    @Autowired
132
    private WarehouseInventoryItemRepository warehouseInventoryItemRepository;
133
 
134
    @Autowired
135
    private LineItemImeisRepository lineItemImeisRepository;
35394 amit 136
 
31920 amit.gupta 137
    @Autowired
138
    private InventoryItemRepository inventoryItemRepository;
139
 
35394 amit 140
    @Autowired
141
    private OfferEligibleImeiRepository offerEligibleImeiRepository;
142
 
143
    // Dependencies - Services
144
    @Autowired
145
    private NotificationService notificationService;
146
 
147
    @Autowired
148
    private RetailerService retailerService;
149
 
150
    @Autowired
151
    private PriceCircularService priceCircularService;
152
 
153
    @Autowired
154
    private WalletService walletService;
155
 
36702 amit 156
    /**
157
     * Evicts all caches related to a specific offer.
158
     *
159
     * Cache inventory (all Redis, 6h TTL unless noted):
160
     *  - monthOfferIds        : Set<Integer> of offer IDs for a month. Key = YearMonth.
161
     *                           Used by /offerHistory admin listing (activeOnly=false).
162
     *  - offer.definition     : CreateOfferRequest per offer. Key = offerId.
163
     *  - catalog.published_yearmonth : Map<fofoId, List<Offer>> for partner-facing published view.
164
     *                           Key = YearMonth. Filtered by activeOnly=true.
165
     *  - offer.slabpayout     : Slab payout map per offer. Key = offerId.
166
     *  - offer.achievement    : Sellin/sellout achievement per (offerId, fofoId). 30 min TTL.
167
     *  - todayOffers          : Today's offers per (brand, fofoId). 60 min TTL (redisShortCacheManager).
168
     */
31747 amit.gupta 169
    @Override
36049 amit 170
    public void evictOfferCaches(int offerId) {
171
        Offer offer = offerRepository.selectById(offerId);
37840 amit 172
        for (YearMonth ym : monthsCovered(offer.getStartDate(), offer.getEndDate())) {
173
            evictMonthCaches(ym);
174
        }
36049 amit 175
        redisCacheManager.getCache("offer.definition").evict(offerId);
176
        redisCacheManager.getCache("offer.slabpayout").evict(offerId);
177
        redisCacheManager.getCache("offer.achievement").clear();
178
    }
179
 
37840 amit 180
    // Month caches hold every offer overlapping the month, so an offer lives in each month from start to end
181
    private static List<YearMonth> monthsCovered(LocalDateTime startDate, LocalDateTime endDate) {
182
        List<YearMonth> months = new ArrayList<>();
183
        YearMonth last = YearMonth.from(endDate);
184
        for (YearMonth ym = YearMonth.from(startDate); !ym.isAfter(last); ym = ym.plusMonths(1)) {
185
            months.add(ym);
186
        }
187
        return months;
188
    }
189
 
36049 amit 190
    @Override
36521 amit 191
    public void evictOfferDefinitionCache(int offerId) {
192
        redisCacheManager.getCache("offer.definition").evict(offerId);
193
    }
194
 
195
    @Override
36702 amit 196
    public void evictMonthCaches(YearMonth yearMonth) {
197
        redisCacheManager.getCache("monthOfferIds").evict(yearMonth);
198
        redisCacheManager.getCache("catalog.published_yearmonth").evict(yearMonth);
199
        redisShortCacheManager.getCache("todayOffers").clear();
200
    }
201
 
202
    @Override
36633 amit 203
    @Transactional(propagation = Propagation.REQUIRES_NEW)
204
    public List<Offer> activateOffers(List<Integer> offerIds, boolean active) throws ProfitMandiBusinessException {
205
        List<Offer> offers = offerRepository.selectAllByIds(offerIds);
206
        offers = offers.stream().filter(x -> x.isActive() != active).collect(Collectors.toList());
207
        for (Offer offer : offers) {
208
            offer.setActive(active);
209
        }
210
        return offers;
211
    }
212
 
213
    @Override
31747 amit.gupta 214
    public void addOfferService(CreateOfferRequest createOfferRequest) throws ProfitMandiBusinessException {
215
        LOGGER.info("createOfferRequest  -- {}", createOfferRequest);
216
        this.createOffer(createOfferRequest);
217
        this.createTargetSlabs(createOfferRequest);
218
    }
27877 amit.gupta 219
 
31747 amit.gupta 220
    private void createOffer(CreateOfferRequest createOfferRequest) {
221
        Offer offer = new Offer();
222
        offer.setName(createOfferRequest.getName());
223
        offer.setTargetType(createOfferRequest.getTargetType());
224
        offer.setBooster(createOfferRequest.isBooster());
225
        offer.setPayoutType(createOfferRequest.getPayoutType());
226
        offer.setSchemeType(createOfferRequest.getSchemeType());
227
        offer.setBaseCriteia(createOfferRequest.isBaseCriteria());
228
        offer.setEndDate(createOfferRequest.getEndDate());
229
        offer.setStartDate(createOfferRequest.getStartDate());
230
        offer.setBrandSharePercentage(createOfferRequest.getBrandShareTerms());
231
        offer.setSellinPercentage(createOfferRequest.getSellinPercentage());
232
        offer.setOfferNotes(createOfferRequest.getOfferNotes());
233
        offer.setActivationBrands(createOfferRequest.getActivationBrands());
234
        offer.setTerms(createOfferRequest.getTerms());
235
        offer.setItemCriteria(gson.toJson(createOfferRequest.getItemCriteria()));
236
        offer.setPartnerCriteria(gson.toJson(createOfferRequest.getPartnerCriteria()));
32070 amit.gupta 237
        offer.setDiscount(createOfferRequest.isDiscount());
36451 amit 238
        offer.setReference(createOfferRequest.getReference());
31747 amit.gupta 239
        offerRepository.persist(offer);
240
        createOfferRequest.setId(offer.getId());
241
    }
27877 amit.gupta 242
 
31747 amit.gupta 243
    @Override
33247 ranu 244
    public List<CreateOfferRequest> getPublishedOffers(int fofoId, YearMonth yearMonth) throws ProfitMandiBusinessException {
36049 amit 245
        // Past months (>1 month ago): achievement is frozen, cache the full result
246
        if (yearMonth.isBefore(YearMonth.now().minusMonths(1))) {
247
            return offerServiceProxy.getPublishedOffersCached(fofoId, yearMonth);
248
        }
249
        // Current/recent month: assemble live from cached building blocks
250
        return assemblePublishedOffers(fofoId, yearMonth);
251
    }
252
 
253
    @Cacheable(value = "publishedOffersWithAchievement.past", cacheManager = "redisCacheManager")
254
    public List<CreateOfferRequest> getPublishedOffersCached(int fofoId, YearMonth yearMonth) throws ProfitMandiBusinessException {
255
        return assemblePublishedOffers(fofoId, yearMonth);
256
    }
257
 
258
    private List<CreateOfferRequest> assemblePublishedOffers(int fofoId, YearMonth yearMonth) throws ProfitMandiBusinessException {
35394 amit 259
        Map<Integer, List<Offer>> publishedMapByPartner = offerRepository.selectAllPublishedMapByPartner(yearMonth);
260
        List<Offer> publishedOffers = publishedMapByPartner != null ? publishedMapByPartner.get(fofoId) : null;
31747 amit.gupta 261
        List<CreateOfferRequest> createOfferRequests = new ArrayList<>();
262
        if (publishedOffers != null) {
263
            for (Offer offer : publishedOffers) {
36049 amit 264
                CreateOfferRequest copy = deepCopy(this.getCreateOfferRequest(offer));
265
                setCriteriaPayoutAchieved(fofoId, copy);
266
                createOfferRequests.add(copy);
31747 amit.gupta 267
            }
268
        }
269
        return createOfferRequests;
270
    }
27877 amit.gupta 271
 
31747 amit.gupta 272
    private void setCriteriaPayoutAchieved(int fofoId, CreateOfferRequest createOfferRequest) {
36049 amit 273
        Map<Integer, Long> criteriaTransactionMap;
31747 amit.gupta 274
        if (createOfferRequest.getSchemeType().equals(OfferSchemeType.SELLIN)) {
36049 amit 275
            criteriaTransactionMap = offerRepository.getPurchaseSumForPartner(
276
                    createOfferRequest.getId(), fofoId, createOfferRequest);
31747 amit.gupta 277
        } else {
36049 amit 278
            criteriaTransactionMap = offerRepository.getSalesSumForPartner(
279
                    createOfferRequest.getId(), fofoId, createOfferRequest);
31747 amit.gupta 280
        }
281
        List<com.spice.profitmandi.dao.model.ItemCriteriaPayout> itemCriteriaPayouts = createOfferRequest
282
                .getTargetSlabs().get(0).getItemCriteriaPayouts();
27877 amit.gupta 283
 
31747 amit.gupta 284
        for (com.spice.profitmandi.dao.model.ItemCriteriaPayout itemCriteriaPayout : itemCriteriaPayouts) {
285
            itemCriteriaPayout.setNextSlab(null);
286
            long saleAmount = 0;
287
            if (criteriaTransactionMap != null
288
                    && criteriaTransactionMap.containsKey(itemCriteriaPayout.getItemCriteria().getId())) {
31853 amit.gupta 289
                saleAmount = criteriaTransactionMap.containsKey(0) ? criteriaTransactionMap.get(0) : criteriaTransactionMap.get(itemCriteriaPayout.getItemCriteria().getId());
31747 amit.gupta 290
            }
291
            itemCriteriaPayout.setAchievedValue(saleAmount);
292
            List<com.spice.profitmandi.service.offers.PayoutSlab> payoutSlabs = itemCriteriaPayout.getPayoutSlabs();
293
            for (int i = 0; i < payoutSlabs.size(); i++) {
294
                com.spice.profitmandi.service.offers.PayoutSlab beginSlab = payoutSlabs.get(i);
295
                com.spice.profitmandi.service.offers.PayoutSlab endSlab = null;
296
                if (payoutSlabs.size() - 1 > i) {
297
                    endSlab = payoutSlabs.get(i + 1);
298
                }
299
                if (beginSlab.getOnwardsAmount() > saleAmount) {
300
                    itemCriteriaPayout.setShortValue(beginSlab.getOnwardsAmount() - saleAmount);
301
                    itemCriteriaPayout.setNextSlab(beginSlab);
302
                    break;
303
                }
304
                if (endSlab != null) {
305
                    if (beginSlab.getOnwardsAmount() <= saleAmount && endSlab.getOnwardsAmount() > saleAmount) {
306
                        itemCriteriaPayout.setCurrentSlab(beginSlab);
307
                        beginSlab.setSelected(true);
308
                        itemCriteriaPayout.setNextSlab(endSlab);
309
                        itemCriteriaPayout.setShortValue(endSlab.getOnwardsAmount() - saleAmount);
310
                        break;
311
                    }
312
                } else {
313
                    beginSlab.setSelected(true);
314
                    itemCriteriaPayout.setCurrentSlab(beginSlab);
315
                }
316
            }
317
        }
318
    }
27877 amit.gupta 319
 
31747 amit.gupta 320
    @Override
36521 amit 321
    @Cacheable(value = "monthOfferIds", cacheManager = "redisCacheManager")
322
    public Set<Integer> getMonthOfferIds(YearMonth yearMonth) throws ProfitMandiBusinessException {
323
        List<Offer> allOffers = offerRepository.selectAll(yearMonth, false);
324
        return allOffers.stream().map(Offer::getId).collect(Collectors.toSet());
325
    }
326
 
327
    @Override
33247 ranu 328
    public Map<Integer, CreateOfferRequest> getAllOffers(YearMonth yearMonth) throws ProfitMandiBusinessException {
36521 amit 329
        Set<Integer> ids = offerServiceProxy.getMonthOfferIds(yearMonth);
330
        Map<Integer, CreateOfferRequest> result = new HashMap<>();
331
        for (Integer id : ids) {
332
            result.put(id, offerServiceProxy.getOfferDefinition(id));
31747 amit.gupta 333
        }
36521 amit 334
        return result;
31747 amit.gupta 335
    }
27877 amit.gupta 336
 
36049 amit 337
    private CreateOfferRequest deepCopy(CreateOfferRequest source) {
338
        return gson.fromJson(gson.toJson(source), CreateOfferRequest.class);
339
    }
340
 
31747 amit.gupta 341
    @Override
36049 amit 342
    @Cacheable(value = "offer.definition", cacheManager = "redisCacheManager", key = "#offerId")
343
    public CreateOfferRequest getOfferDefinition(int offerId) throws ProfitMandiBusinessException {
344
        Offer offer = offerRepository.selectById(offerId);
345
        return this.getCreateOfferRequest(offer);
346
    }
347
 
348
    @Override
33247 ranu 349
    public CreateOfferRequest getOffer(int fofoId, int offerId) throws ProfitMandiBusinessException {
36049 amit 350
        CreateOfferRequest definition = offerServiceProxy.getOfferDefinition(offerId);
31747 amit.gupta 351
        if (fofoId > 0) {
36049 amit 352
            CreateOfferRequest copy = deepCopy(definition);
353
            copy.setCriteriaQtyAmountModel(this.getCriteriaQtyAmounModelMap(copy, fofoId));
354
            return copy;
31747 amit.gupta 355
        }
36049 amit 356
        return definition;
31747 amit.gupta 357
    }
27877 amit.gupta 358
 
31747 amit.gupta 359
    @Override
33247 ranu 360
    public CreateOfferRequest getCreateOfferRequest(Offer fromOffer) throws ProfitMandiBusinessException {
31747 amit.gupta 361
        CreateOfferRequest createOfferRequest = new CreateOfferRequest();
362
        createOfferRequest.setName(fromOffer.getName());
32023 amit.gupta 363
        createOfferRequest.setDiscount(fromOffer.isDiscount());
31747 amit.gupta 364
        createOfferRequest.setTargetType(fromOffer.getTargetType());
365
        createOfferRequest.setPayoutType(fromOffer.getPayoutType());
366
        createOfferRequest.setSchemeType(fromOffer.getSchemeType());
367
        createOfferRequest.setActivationBrands(fromOffer.getActivationBrands());
368
        createOfferRequest.setEndDate(fromOffer.getEndDate());
369
        createOfferRequest.setProcessTimestamp(fromOffer.getProcessedTimestamp());
370
        createOfferRequest.setStartDate(fromOffer.getStartDate());
371
        createOfferRequest.setBooster(fromOffer.isBooster());
372
        createOfferRequest.setActive(fromOffer.isActive());
373
        createOfferRequest.setSellinPercentage(fromOffer.getSellinPercentage());
374
        createOfferRequest.setBrandShareTerms(fromOffer.getBrandSharePercentage());
375
        createOfferRequest.setOfferNotes(fromOffer.getOfferNotes());
376
        createOfferRequest.setTerms(fromOffer.getTerms());
377
        createOfferRequest.setBaseCriteria(fromOffer.isBaseCriteia());
378
        createOfferRequest.setItemCriteria(
379
                gson.fromJson(fromOffer.getItemCriteria(), com.spice.profitmandi.service.offers.ItemCriteria.class));
380
        createOfferRequest.setPartnerCriteria(gson.fromJson(fromOffer.getPartnerCriteria(), PartnerCriteria.class));
381
        createOfferRequest.setId(fromOffer.getId());
382
        createOfferRequest.setCreatedOn(fromOffer.getCreatedTimestamp());
36451 amit 383
        createOfferRequest.setReference(fromOffer.getReference());
31747 amit.gupta 384
        createOfferRequest.setItemCriteriaString(
385
                itemCriteriaRepository.getItemCriteriaDescription(createOfferRequest.getItemCriteria()));
386
        List<com.spice.profitmandi.dao.model.TargetSlab> targetSlabs = offerTargetSlabRepository
387
                .getByOfferId(fromOffer.getId());
388
        createOfferRequest.setPartnerCriteriaString(
33030 amit.gupta 389
                this.getPartnerCriteriaString(createOfferRequest.getPartnerCriteria()));
31747 amit.gupta 390
        createOfferRequest.setTargetSlabs(targetSlabs);
35885 amit 391
        if (!targetSlabs.isEmpty() && !targetSlabs.get(0).getItemCriteriaPayouts().isEmpty()) {
392
            for (com.spice.profitmandi.dao.model.ItemCriteriaPayout itemCriteriaPayout : targetSlabs.get(0).getItemCriteriaPayouts()) {
393
                if (!itemCriteriaPayout.getPayoutSlabs().isEmpty()) {
394
                    itemCriteriaPayout.setNextSlab(itemCriteriaPayout.getPayoutSlabs().get(0));
395
                }
396
            }
31747 amit.gupta 397
        }
398
        return createOfferRequest;
399
    }
27877 amit.gupta 400
 
31747 amit.gupta 401
    @Override
33613 amit.gupta 402
    public void reverseAdditionalSelloutSchemes(List<InventoryItem> inventoryItems, String reversalReason) throws ProfitMandiBusinessException {
403
        Map<Integer, List<InventoryItem>> fofoInventoryItemsMap = inventoryItems.stream().collect(Collectors.groupingBy(x -> x.getFofoId()));
404
        for (Map.Entry<Integer, List<InventoryItem>> fofoInventoryItemsEntry : fofoInventoryItemsMap.entrySet()) {
405
            int fofoId = fofoInventoryItemsEntry.getKey();
406
            List<InventoryItem> partnerInventoryItems = fofoInventoryItemsEntry.getValue();
407
            List<OfferPayout> offerPayouts = new ArrayList<>();
408
            LOGGER.info("Reversing schemes for fofoId {}, InventoryItems {}", fofoId, inventoryItems);
409
            //As of now we are not handling non-serialised items
35394 amit 410
            List<InventoryItem> serializedItems = partnerInventoryItems.stream().filter(x -> x.getSerialNumber() != null).collect(Collectors.toList());
411
            if (serializedItems.size() > 0) {
412
                // Batch fetch: collect all serial numbers and fetch in one call per fofoId
413
                Set<String> serialNumbers = serializedItems.stream().map(InventoryItem::getSerialNumber).collect(Collectors.toSet());
414
                offerPayouts = offerPayoutRepository.selectAllBySerialNumbers(fofoId, serialNumbers)
415
                        .stream()
416
                        .filter(x -> x.getRejectTimestamp() == null)
417
                        .collect(Collectors.toList());
33613 amit.gupta 418
                for (OfferPayout offerPayout : offerPayouts) {
419
                    offerPayout.setStatus(SchemePayoutStatus.REJECTED);
420
                    offerPayout.setRejectTimestamp(LocalDateTime.now());
421
                }
422
                Map<Long, Double> offerPayoutAmountMap = offerPayouts.stream().collect(Collectors.groupingBy(x -> x.getOfferId(), Collectors.summingDouble(x -> x.getAmount())));
423
                for (Map.Entry<Long, Double> offerPayoutEntry : offerPayoutAmountMap.entrySet()) {
424
                    List<UserWalletHistory> histories = walletService.getAllByReference(fofoId, offerPayoutEntry.getKey().intValue(), WalletReferenceType.ADDITIONAL_SCHEME);
425
                    if (histories.size() > 0) {
31750 amit.gupta 426
 
33613 amit.gupta 427
                        walletService.rollbackAmountFromWallet(fofoId, offerPayoutEntry.getValue().floatValue(), offerPayoutEntry.getKey().intValue(),
428
                                WalletReferenceType.ADDITIONAL_SCHEME, reversalReason, LocalDateTime.now());
429
                    }
31750 amit.gupta 430
                }
431
            }
31747 amit.gupta 432
        }
433
    }
30684 amit.gupta 434
 
36103 amit 435
    @Override
436
    public void restoreAdditionalSelloutSchemes(List<InventoryItem> inventoryItems, String restoreReason)
437
            throws ProfitMandiBusinessException {
438
        Map<Integer, List<InventoryItem>> fofoInventoryItemsMap = inventoryItems.stream()
439
                .collect(Collectors.groupingBy(InventoryItem::getFofoId));
440
        for (Map.Entry<Integer, List<InventoryItem>> entry : fofoInventoryItemsMap.entrySet()) {
441
            int fofoId = entry.getKey();
442
            List<InventoryItem> partnerItems = entry.getValue();
443
 
444
            List<InventoryItem> serializedItems = partnerItems.stream()
445
                    .filter(x -> x.getSerialNumber() != null)
446
                    .collect(Collectors.toList());
447
            if (!serializedItems.isEmpty()) {
448
                Set<String> serialNumbers = serializedItems.stream()
449
                        .map(InventoryItem::getSerialNumber).collect(Collectors.toSet());
450
                List<OfferPayout> offerPayouts = offerPayoutRepository
451
                        .selectAllBySerialNumbers(fofoId, serialNumbers).stream()
452
                        .filter(x -> x.getRejectTimestamp() != null
453
                                && SchemePayoutStatus.REJECTED.equals(x.getStatus()))
454
                        .collect(Collectors.toList());
455
 
456
                for (OfferPayout offerPayout : offerPayouts) {
457
                    offerPayout.setStatus(SchemePayoutStatus.CREDITED);
458
                    offerPayout.setRejectTimestamp(null);
459
                }
460
 
461
                Map<Long, Double> offerPayoutAmountMap = offerPayouts.stream()
462
                        .collect(Collectors.groupingBy(OfferPayout::getOfferId,
463
                                Collectors.summingDouble(OfferPayout::getAmount)));
464
                for (Map.Entry<Long, Double> offerEntry : offerPayoutAmountMap.entrySet()) {
465
                    if (offerEntry.getValue() > 0) {
466
                        walletService.addAmountToWallet(fofoId, offerEntry.getKey().intValue(),
467
                                WalletReferenceType.ADDITIONAL_SCHEME, restoreReason,
468
                                offerEntry.getValue().floatValue(), LocalDateTime.now());
469
                    }
470
                }
471
            }
472
        }
473
    }
474
 
31747 amit.gupta 475
    private void createTargetSlabs(CreateOfferRequest createOfferRequest) throws ProfitMandiBusinessException {
476
        List<com.spice.profitmandi.dao.model.TargetSlab> targetSlabs = createOfferRequest.getTargetSlabs().stream()
477
                .filter(x -> x.validate()).collect(Collectors.toList());
35394 amit 478
        if (!targetSlabs.isEmpty()) {
31747 amit.gupta 479
            Collections.sort(targetSlabs);
480
            for (com.spice.profitmandi.dao.model.TargetSlab targetSlab : targetSlabs) {
481
                if (targetSlab.validate()) {
482
                    List<ItemCriteriaPayout> itemCriteriaPayouts = targetSlab.getItemCriteriaPayouts();
483
                    for (ItemCriteriaPayout itemCriteriaPayout : itemCriteriaPayouts) {
484
                        ItemCriteria itemCriteria = itemCriteriaRepository.selectById(itemCriteriaPayout.getItemCriteria().getId());
485
                        if (itemCriteriaPayout.getItemCriteria().getId() > 0) {
486
                            itemCriteriaPayout.getItemCriteria().setId(0);
487
                        } else {
488
                            String itemCriteriaJson = gson.toJson(itemCriteriaPayout.getItemCriteria());
489
                            itemCriteria = itemCriteriaRepository.selectByCriteria(itemCriteriaJson);
490
                            // ItemCriteria Only once
491
                            if (itemCriteria == null) {
492
                                itemCriteria = new ItemCriteria();
493
                                itemCriteria.setCriteria(gson.toJson(itemCriteriaPayout.getItemCriteria()));
494
                                itemCriteriaRepository.persist(itemCriteria);
495
                            }
496
                        }
497
                        for (PayoutSlab payoutSlab : itemCriteriaPayout.getPayoutSlabs()) {
31903 amit.gupta 498
                            TargetSlabEntity targetSlabEntity = new TargetSlabEntity();
499
                            targetSlabEntity.setOfferId(createOfferRequest.getId());
500
                            targetSlabEntity.setOnwardsTarget(targetSlab.getOnwardsAmount());
501
                            targetSlabEntity.setTargetDescription(targetSlab.getTargetDescription());
502
                            targetSlabEntity.setPayoutTarget(payoutSlab.getOnwardsAmount());
503
                            targetSlabEntity.setPayoutValue(payoutSlab.getPayoutAmount());
504
                            targetSlabEntity.setItemCriteriaId(itemCriteria.getId());
505
                            targetSlabEntity.setAmountType(itemCriteriaPayout.getAmountType());
32979 amit.gupta 506
                            targetSlabEntity.setStartDate(itemCriteriaPayout.getStartDate());
507
                            targetSlabEntity.setEndDate(itemCriteriaPayout.getEndDate());
31903 amit.gupta 508
                            offerTargetSlabRepository.persist(targetSlabEntity);
31747 amit.gupta 509
                        }
510
                    }
511
                }
512
            }
27877 amit.gupta 513
 
31747 amit.gupta 514
        } else {
515
            throw new ProfitMandiBusinessException("Invalid Target Slabs", "Invalid Target", "");
516
        }
27877 amit.gupta 517
 
31747 amit.gupta 518
    }
27877 amit.gupta 519
 
31747 amit.gupta 520
    @Override
33247 ranu 521
    public List<CreateOfferRequest> getPublishedOffers(LocalDate date, int fofoId, int catalogId) throws ProfitMandiBusinessException {
35394 amit 522
        Map<Integer, List<Offer>> publishedMapByPartner = offerRepository.selectAllPublishedMapByPartner(YearMonth.from(date));
523
        List<Offer> publishedOffers = publishedMapByPartner != null ? publishedMapByPartner.get(fofoId) : null;
31747 amit.gupta 524
        List<CreateOfferRequest> createOfferRequests = new ArrayList<>();
525
        if (publishedOffers != null) {
526
            for (Offer offer : publishedOffers) {
527
                boolean found = false;
528
                List<com.spice.profitmandi.dao.model.TargetSlab> targetSlabs = offerTargetSlabRepository
529
                        .getByOfferId(offer.getId());
530
                CreateOfferRequest createOfferRequest = this.getCreateOfferRequest(offer);
531
                createOfferRequest.setTargetSlabs(targetSlabs);
532
                this.setCriteriaPayoutAchieved(fofoId, createOfferRequest);
533
                Set<com.spice.profitmandi.service.offers.ItemCriteria> itemCriteriaSet = targetSlabs.stream()
534
                        .flatMap(x -> x.getItemCriteriaPayouts().stream()).map(x -> x.getItemCriteria()).distinct()
535
                        .filter(x -> itemRepository.containsModel(x, catalogId)).collect(Collectors.toSet());
29499 amit.gupta 536
 
31747 amit.gupta 537
                for (com.spice.profitmandi.dao.model.TargetSlab targetSlab : targetSlabs) {
538
                    targetSlab.setItemCriteriaPayouts(targetSlab.getItemCriteriaPayouts().stream()
539
                            .filter(x -> itemCriteriaSet.contains(x.getItemCriteria())).collect(Collectors.toList()));
540
                    if (targetSlab.getItemCriteriaPayouts().size() > 0) {
541
                        found = true;
542
                    }
543
                }
544
                if (found) {
545
                    createOfferRequests.add(createOfferRequest);
546
                }
547
            }
548
        }
29783 amit.gupta 549
 
31747 amit.gupta 550
        return createOfferRequests;
551
    }
29783 amit.gupta 552
 
31747 amit.gupta 553
    @Override
554
    public void createOffers(InputStream fileInputStream) throws Exception {
555
        Map<CreateOfferRequest, List<PartnerTargetModel>> offerPartnerTargetMap = this.parseFromExcel(fileInputStream);
32868 amit.gupta 556
        Set<YearMonth> ymListToEvict = new HashSet<>();
31747 amit.gupta 557
        for (Map.Entry<CreateOfferRequest, List<PartnerTargetModel>> partnerTargetEntry : offerPartnerTargetMap
558
                .entrySet()) {
559
            CreateOfferRequest createOfferRequest = partnerTargetEntry.getKey();
560
            Map<List<Integer>, List<Integer>> targetPartnerMap = partnerTargetEntry.getValue().stream()
561
                    .collect(Collectors.groupingBy(PartnerTargetModel::getTargets,
562
                            Collectors.mapping(PartnerTargetModel::getFofoId, Collectors.toList())));
563
            for (Map.Entry<List<Integer>, List<Integer>> targetPartnersEntry : targetPartnerMap.entrySet()) {
564
                List<Integer> fofoIds = createOfferRequest.getPartnerCriteria().getFofoIds();
565
                List<Integer> filterFofoIds = targetPartnersEntry.getValue().stream().filter(x -> !fofoIds.contains(x))
566
                        .collect(Collectors.toList());
567
                LOGGER.info("FofoIds {}", filterFofoIds);
568
                List<Integer> targets = targetPartnersEntry.getKey();
569
                LOGGER.info("Targets  {}", targets);
29806 amit.gupta 570
 
31747 amit.gupta 571
                createOfferRequest.getPartnerCriteria().setFofoIds(filterFofoIds);
572
                int counter = 0;
573
                List<ItemCriteriaPayout> itemCriteriaPayouts = createOfferRequest.getTargetSlabs().get(0)
574
                        .getItemCriteriaPayouts();
575
                List<PayoutSlab> payoutSlabs = itemCriteriaPayouts.stream().flatMap(x -> x.getPayoutSlabs().stream()).collect(Collectors.toList());
576
                for (PayoutSlab payoutSlab : payoutSlabs) {
577
                    payoutSlab.setOnwardsAmount(targets.get(counter));
578
                    counter++;
579
                }
580
                this.addOfferService(createOfferRequest);
581
            }
37840 amit 582
            ymListToEvict.addAll(monthsCovered(createOfferRequest.getStartDate(), createOfferRequest.getEndDate()));
31747 amit.gupta 583
        }
32868 amit.gupta 584
        for (YearMonth ymToEvict : ymListToEvict) {
36702 amit 585
            evictMonthCaches(ymToEvict);
32868 amit.gupta 586
        }
31747 amit.gupta 587
    }
29783 amit.gupta 588
 
31747 amit.gupta 589
    private Map<CreateOfferRequest, List<PartnerTargetModel>> parseFromExcel(InputStream inputStream)
590
            throws ProfitMandiBusinessException {
29783 amit.gupta 591
 
31747 amit.gupta 592
        Map<CreateOfferRequest, List<PartnerTargetModel>> offerPartnerTargetMap = new HashMap<>();
593
        XSSFWorkbook myWorkBook = null;
594
        try {
595
            myWorkBook = new XSSFWorkbook(inputStream);
596
            myWorkBook.setMissingCellPolicy(MissingCellPolicy.RETURN_BLANK_AS_NULL);
597
            for (int i = 0; i < myWorkBook.getNumberOfSheets(); i++) {
29683 amit.gupta 598
 
31747 amit.gupta 599
                XSSFSheet mySheet = myWorkBook.getSheetAt(i);
600
                int offerId = Integer.parseInt(mySheet.getSheetName());
601
                CreateOfferRequest existingOffer = this.getOffer(0, offerId);
602
                List<PartnerTargetModel> partnerTargetModels = new ArrayList<>();
603
                offerPartnerTargetMap.put(existingOffer, partnerTargetModels);
604
                this.printIterator(mySheet);
605
                LOGGER.info("rowCellNum {}", mySheet.getLastRowNum());
606
                for (int rowNumber = 1; rowNumber <= mySheet.getLastRowNum(); rowNumber++) {
607
                    XSSFRow row = mySheet.getRow(rowNumber);
608
                    LOGGER.info("row {}", row);
609
                    PartnerTargetModel partnerTargetModel = new PartnerTargetModel();
29783 amit.gupta 610
 
31747 amit.gupta 611
                    if (row.getCell(0) != null && row.getCell(0).getCellTypeEnum() == CellType.NUMERIC) {
612
                        partnerTargetModel.setFofoId((int) row.getCell(0).getNumericCellValue());
613
                    } else {
614
                        ProfitMandiBusinessException profitMandiBusinessException = new ProfitMandiBusinessException(
615
                                "FOFO ID", row.getCell(0).toString(), "TGLSTNG_VE_1010");
616
                        LOGGER.error("Excel file parse error : ", profitMandiBusinessException);
617
                        throw profitMandiBusinessException;
618
                    }
619
                    List<Integer> targets = new ArrayList<>();
620
                    long targetsSize = existingOffer.getTargetSlabs().get(0).getItemCriteriaPayouts().stream().flatMap(x -> x.getPayoutSlabs().stream()).collect(Collectors.counting());
621
                    for (int cellNumber = 1; cellNumber <= targetsSize; cellNumber++) {
622
                        if (row.getCell(cellNumber) != null
623
                                && row.getCell(cellNumber).getCellTypeEnum() == CellType.NUMERIC) {
624
                            targets.add((int) row.getCell(cellNumber).getNumericCellValue());
625
                        } else {
626
                            ProfitMandiBusinessException profitMandiBusinessException = new ProfitMandiBusinessException(
627
                                    "Target Column issue at " + rowNumber + ", " + cellNumber, row.getCell(cellNumber),
628
                                    "Invalid target");
629
                            LOGGER.error("Excel file parse error : ", profitMandiBusinessException);
630
                            throw profitMandiBusinessException;
631
                        }
632
                    }
633
                    partnerTargetModel.setTargets(targets);
634
                    partnerTargetModels.add(partnerTargetModel);
635
                }
636
            }
637
            myWorkBook.close();
638
        } catch (ProfitMandiBusinessException pbse) {
639
            throw pbse;
640
        } catch (IOException ioException) {
641
            ioException.printStackTrace();
642
            throw new ProfitMandiBusinessException(ProfitMandiConstants.EXCEL_FILE, ioException.getMessage(),
643
                    "EXL_VE_1000");
644
        } finally {
645
            if (myWorkBook != null) {
646
                try {
647
                    myWorkBook.close();
648
                } catch (IOException e) {
649
                    // TODO Auto-generated catch block
650
                    e.printStackTrace();
651
                }
652
            }
653
        }
654
        LOGGER.info("offerPartnerTargetMap {}", offerPartnerTargetMap);
655
        return offerPartnerTargetMap;
656
    }
29783 amit.gupta 657
 
31747 amit.gupta 658
    private void printIterator(XSSFSheet sheet) {
659
        Iterator<Row> rowIterator = sheet.iterator();
660
        while (rowIterator.hasNext()) {
661
            Row row = rowIterator.next();
35394 amit 662
            StringBuilder rowContent = new StringBuilder();
31747 amit.gupta 663
            Iterator<Cell> cellIterator = row.cellIterator();
29683 amit.gupta 664
 
31747 amit.gupta 665
            while (cellIterator.hasNext()) {
666
                Cell cell = cellIterator.next();
667
                switch (cell.getCellType()) {
668
                    case Cell.CELL_TYPE_NUMERIC:
35394 amit 669
                        rowContent.append(cell.getNumericCellValue()).append("\t");
31747 amit.gupta 670
                        break;
671
                    case Cell.CELL_TYPE_STRING:
35394 amit 672
                        rowContent.append(cell.getStringCellValue()).append("\t");
31747 amit.gupta 673
                        break;
674
                }
675
            }
35394 amit 676
            LOGGER.debug("Row content: {}", rowContent);
31747 amit.gupta 677
        }
678
    }
29683 amit.gupta 679
 
31747 amit.gupta 680
    @Override
681
    public Map<Integer, CreateOfferRequest> getPublishedOffers(LocalDate date, int fofoId, String brand) {
682
        // TODO Auto-generated method stub
683
        return null;
684
    }
30684 amit.gupta 685
 
31747 amit.gupta 686
    @Override
36374 ranu 687
    public List<CreateOfferRequest> getActiveOffers(int fofoId) throws ProfitMandiBusinessException {
688
        List<Offer> activeOffers = offerRepository.selectCurrentlyActiveForPartner(fofoId);
689
        List<CreateOfferRequest> result = new ArrayList<>();
690
 
691
        for (Offer offer : activeOffers) {
692
            CreateOfferRequest copy = deepCopy(this.getCreateOfferRequest(offer));
693
            setCriteriaPayoutAchieved(fofoId, copy);
694
            result.add(copy);
695
        }
696
 
697
        return result;
698
    }
699
 
700
    @Override
32043 amit.gupta 701
    @Cacheable(value = "slabPayoutMap1", cacheManager = "oneDayCacheManager")
33247 ranu 702
    public Map<Integer, Map<Integer, Long>> getSlabPayoutMap(CreateOfferRequest createOfferRequest) throws ProfitMandiBusinessException {
31747 amit.gupta 703
        Map<Integer, Map<Integer, Long>> catalogSlabPayoutMap = new HashMap<>();
704
        com.spice.profitmandi.dao.model.TargetSlab targetSlab = createOfferRequest.getTargetSlabs().get(0);
705
        List<ItemCriteriaPayout> payouts = targetSlab.getItemCriteriaPayouts();
29783 amit.gupta 706
 
31747 amit.gupta 707
        for (ItemCriteriaPayout itemCriteriaPayout : payouts) {
708
            com.spice.profitmandi.service.offers.ItemCriteria itemCriteria = itemCriteriaPayout.getItemCriteria();
709
            List<Integer> catalogIds = itemRepository.getCatalogIds(itemCriteria);
710
            for (PayoutSlab payoutSlab : Lists.reverse(itemCriteriaPayout.getPayoutSlabs())) {
711
                if (itemCriteriaPayout.getAmountType().equals(AmountType.FIXED)) {
712
                    for (Integer catalogId : catalogIds) {
713
                        if (!catalogSlabPayoutMap.containsKey(catalogId)) {
714
                            catalogSlabPayoutMap.put(catalogId, new LinkedHashMap<>());
715
                        }
716
                        catalogSlabPayoutMap.get(catalogId).put(payoutSlab.getOnwardsAmount(),
717
                                (long) payoutSlab.getPayoutAmount());
718
                    }
719
                } else if (itemCriteriaPayout.getAmountType().equals(AmountType.SLAB_FIXED)) {
720
                    for (Integer catalogId : catalogIds) {
721
                        if (!catalogSlabPayoutMap.containsKey(catalogId)) {
722
                            catalogSlabPayoutMap.put(catalogId, new LinkedHashMap<>());
723
                        }
724
                        catalogSlabPayoutMap.get(catalogId).put(payoutSlab.getOnwardsAmount(),
725
                                (long) (payoutSlab.getPayoutAmount() / payoutSlab.getOnwardsAmount()));
726
                    }
727
                } else if (itemCriteriaPayout.getAmountType().equals(AmountType.PERCENTAGE)) {
728
                    Map<Integer, TagListing> tagListingsMap = tagListingRepository.selectAllByCatalogIds(catalogIds);
729
                    for (Map.Entry<Integer, TagListing> tagListingEntry : tagListingsMap.entrySet()) {
730
                        TagListing tagListing = tagListingEntry.getValue();
731
                        if (!catalogSlabPayoutMap.containsKey(tagListingEntry.getKey())) {
732
                            catalogSlabPayoutMap.put(tagListingEntry.getKey(), new LinkedHashMap<>());
733
                        }
734
                        catalogSlabPayoutMap.get(tagListingEntry.getKey()).put(payoutSlab.getOnwardsAmount(),
735
                                (long) (tagListing.getSellingPrice() * payoutSlab.getPayoutAmount() / 100));
736
                    }
737
                }
738
            }
739
        }
740
        return catalogSlabPayoutMap;
741
    }
742
 
31903 amit.gupta 743
    @Override
36049 amit 744
    @Cacheable(value = "offer.slabpayout", cacheManager = "redisCacheManager", key = "#createOfferRequest.id")
31903 amit.gupta 745
    public Map<Integer, Map<Integer, AmountModel>> getSlabPayoutMapNew(CreateOfferRequest createOfferRequest) {
746
        Map<Integer, Map<Integer, AmountModel>> catalogSlabPayoutMap = new HashMap<>();
747
        com.spice.profitmandi.dao.model.TargetSlab targetSlab = createOfferRequest.getTargetSlabs().get(0);
748
        List<ItemCriteriaPayout> payouts = targetSlab.getItemCriteriaPayouts();
749
 
750
        for (ItemCriteriaPayout itemCriteriaPayout : payouts) {
751
            com.spice.profitmandi.service.offers.ItemCriteria itemCriteria = itemCriteriaPayout.getItemCriteria();
752
            List<Integer> catalogIds = itemRepository.getCatalogIds(itemCriteria);
753
            for (PayoutSlab payoutSlab : Lists.reverse(itemCriteriaPayout.getPayoutSlabs())) {
754
                if (itemCriteriaPayout.getAmountType().equals(AmountType.FIXED)) {
755
                    for (Integer catalogId : catalogIds) {
756
                        if (!catalogSlabPayoutMap.containsKey(catalogId)) {
757
                            catalogSlabPayoutMap.put(catalogId, new LinkedHashMap<>());
758
                        }
759
                        AmountModel amountModel = new AmountModel();
760
                        amountModel.setAmountType(AmountType.FIXED);
761
                        amountModel.setAmount(payoutSlab.getPayoutAmount());
32021 amit.gupta 762
                        amountModel.setDiscount(createOfferRequest.isDiscount());
31903 amit.gupta 763
                        catalogSlabPayoutMap.get(catalogId).put(payoutSlab.getOnwardsAmount(),
764
                                amountModel);
765
                    }
766
                } else if (itemCriteriaPayout.getAmountType().equals(AmountType.SLAB_FIXED)) {
767
                    for (Integer catalogId : catalogIds) {
768
                        if (!catalogSlabPayoutMap.containsKey(catalogId)) {
769
                            catalogSlabPayoutMap.put(catalogId, new LinkedHashMap<>());
770
                        }
771
 
772
                        AmountModel amountModel = new AmountModel();
773
                        amountModel.setAmountType(AmountType.FIXED);
32021 amit.gupta 774
                        amountModel.setDiscount(createOfferRequest.isDiscount());
31903 amit.gupta 775
                        amountModel.setAmount(payoutSlab.getPayoutAmount() / payoutSlab.getOnwardsAmount());
776
                        catalogSlabPayoutMap.get(catalogId).put(payoutSlab.getOnwardsAmount(),
777
                                amountModel);
778
                    }
779
                } else if (itemCriteriaPayout.getAmountType().equals(AmountType.PERCENTAGE)) {
780
                    for (Integer catalogId : catalogIds) {
781
                        if (!catalogSlabPayoutMap.containsKey(catalogId)) {
782
                            catalogSlabPayoutMap.put(catalogId, new LinkedHashMap<>());
783
                        }
784
                        AmountModel amountModel = new AmountModel();
785
                        amountModel.setAmountType(AmountType.PERCENTAGE);
786
                        amountModel.setAmount(payoutSlab.getPayoutAmount());
32021 amit.gupta 787
                        amountModel.setDiscount(createOfferRequest.isDiscount());
31903 amit.gupta 788
                        catalogSlabPayoutMap.get(catalogId).put(payoutSlab.getOnwardsAmount(),
789
                                amountModel);
790
                    }
791
                }
792
            }
793
        }
794
        return catalogSlabPayoutMap;
795
    }
796
 
31920 amit.gupta 797
 
798
    private double getAmount(InventoryPayoutModel inventoryPayoutModel, AmountModel amountModel) {
799
        double rollout = 0;
800
        if (amountModel.getAmountType().equals(AmountType.PERCENTAGE)) {
801
            double effectiveDp = inventoryPayoutModel.getDp() - inventoryPayoutModel.getFixedAmount();
802
            double totalPercentage = inventoryPayoutModel.getPercentageAmount() + amountModel.getAmount();
803
            rollout = effectiveDp * (totalPercentage / (100 + totalPercentage) - (inventoryPayoutModel.getPercentageAmount() / (100 + inventoryPayoutModel.getPercentageAmount())));
804
        } else {
805
            rollout = amountModel.getAmount() * (100 / (100 + inventoryPayoutModel.getPercentageAmount()));
806
        }
807
        return rollout;
808
    }
809
 
35394 amit 810
    @Override
811
    public Map<Integer, QtyAmountModel> getCriteriaQtyAmounModelMap(CreateOfferRequest createOfferRequest, int fofoId) throws ProfitMandiBusinessException {
812
        Map<Integer, QtyAmountModel> qtyAmountMap;
813
        if (createOfferRequest.getSchemeType().equals(OfferSchemeType.SELLIN)) {
814
            qtyAmountMap = getCriteriaQtyAmountModelMapForSellin(createOfferRequest, fofoId);
815
        } else {
816
            qtyAmountMap = getCriteriaQtyAmountModelMapForSelloutAndActivation(createOfferRequest, fofoId);
817
        }
818
        LOGGER.info("Qty Amount Map {}", qtyAmountMap);
819
        return qtyAmountMap;
820
    }
34217 amit.gupta 821
 
35667 amit 822
    private PayoutSlab findEligibleSlab(List<PayoutSlab> slabs, int achievedValue) {
823
        PayoutSlab eligibleSlab = null;
824
        for (PayoutSlab slab : slabs) {
825
            if (slab.getOnwardsAmount() <= achievedValue) {
826
                eligibleSlab = slab;
827
            } else {
828
                break;
829
            }
830
        }
831
        return eligibleSlab;
832
    }
833
 
35675 amit 834
    private void setSlabProgress(ItemCriteriaPayout itemCriteriaPayout, PayoutSlab eligibleSlab, int achievedValue) {
835
        List<PayoutSlab> slabs = itemCriteriaPayout.getPayoutSlabs();
836
        itemCriteriaPayout.setCurrentSlab(eligibleSlab);
837
        if (eligibleSlab == null) {
838
            if (!slabs.isEmpty()) {
839
                itemCriteriaPayout.setNextSlab(slabs.get(0));
840
                itemCriteriaPayout.setShortValue(slabs.get(0).getOnwardsAmount() - achievedValue);
841
            }
842
        } else {
843
            int idx = slabs.indexOf(eligibleSlab);
844
            if (idx < slabs.size() - 1) {
845
                PayoutSlab next = slabs.get(idx + 1);
846
                itemCriteriaPayout.setNextSlab(next);
847
                itemCriteriaPayout.setShortValue(next.getOnwardsAmount() - achievedValue);
848
            } else {
849
                itemCriteriaPayout.setNextSlab(null);
850
                itemCriteriaPayout.setShortValue(0);
851
            }
852
        }
853
    }
854
 
35667 amit 855
    private double calculateFinalPayout(PayoutSlab eligibleSlab, AmountType amountType,
856
                                        int valueForPercentage, int valueForFixed) {
857
        if (eligibleSlab == null) return 0;
858
        eligibleSlab.setSelected(true);
859
        float payoutRate = eligibleSlab.getPayoutAmount();
860
        if (AmountType.PERCENTAGE.equals(amountType)) {
861
            return (payoutRate * valueForPercentage) / 100;
862
        } else if (AmountType.FIXED.equals(amountType)) {
863
            return payoutRate * valueForFixed;
864
        } else {
865
            return payoutRate;
866
        }
867
    }
868
 
869
    private QtyAmountModel calculateSellinQtyAndValue(List<Order> orders) {
870
        int qty = orders.stream().collect(Collectors.summingInt(x ->
871
                x.getLineItem().getQuantity() - x.getLineItem().getReturnQty()));
872
        int value = orders.stream().collect(Collectors.summingInt(x ->
873
                Math.round(x.getLineItem().getUnitPrice() *
874
                        (x.getLineItem().getQuantity() - x.getLineItem().getReturnQty()))));
875
        return new QtyAmountModel(qty, value);
876
    }
877
 
35394 amit 878
    private Map<Integer, QtyAmountModel> getCriteriaQtyAmountModelMapForSellin(CreateOfferRequest createOfferRequest, int fofoId) throws ProfitMandiBusinessException {
879
        Map<Integer, QtyAmountModel> criteriaQtyAmountMap = new HashMap<>();
880
 
881
        Map<Integer, List<Order>> criteriaOrdersMap = offerRepository.getPartnerWiseSellin(fofoId, createOfferRequest, true);
882
 
35667 amit 883
        List<Order> baseCriteriaOrders = criteriaOrdersMap.get(0);
35394 amit 884
        Integer userBaseQty = null;
885
        Integer userBaseValue = null;
35667 amit 886
        if (baseCriteriaOrders != null && baseCriteriaOrders.size() > 0) {
887
            QtyAmountModel baseModel = calculateSellinQtyAndValue(baseCriteriaOrders);
888
            userBaseQty = baseModel.getQty();
889
            userBaseValue = (int) baseModel.getAmount();
890
            criteriaQtyAmountMap.put(0, baseModel);
891
        } else {
892
            criteriaQtyAmountMap.put(0, new QtyAmountModel(0, 0));
35394 amit 893
        }
894
 
895
        LOGGER.info("Processing sellin");
896
        for (ItemCriteriaPayout itemCriteriaPayout : createOfferRequest.getTargetSlabs().get(0).getItemCriteriaPayouts()) {
897
            int criteriaId = itemCriteriaPayout.getItemCriteria().getId();
898
 
899
            QtyAmountModel qtyAmountModel = new QtyAmountModel(0, 0);
35667 amit 900
            criteriaQtyAmountMap.put(criteriaId, qtyAmountModel);
35394 amit 901
 
902
            List<Order> orders = criteriaOrdersMap.get(criteriaId);
35667 amit 903
            if (orders == null || orders.isEmpty()) continue;
904
 
905
            QtyAmountModel criteriaModel = calculateSellinQtyAndValue(orders);
36051 amit 906
            int criteriaQty = criteriaModel.getQty();
907
            int totalBaseQty = criteriaQty;
35667 amit 908
            int totalBaseValue = (int) criteriaModel.getAmount();
35394 amit 909
            if (userBaseQty != null) {
910
                totalBaseQty = userBaseQty;
911
                totalBaseValue = userBaseValue;
912
            }
913
 
914
            int purchasedValue;
915
            if (createOfferRequest.getTargetType().equals(AchievementType.VALUE)) {
916
                purchasedValue = totalBaseValue;
917
            } else {
918
                purchasedValue = totalBaseQty;
919
            }
920
            qtyAmountModel.setQty(totalBaseQty);
921
            qtyAmountModel.setAmount(totalBaseValue);
922
 
35667 amit 923
            PayoutSlab eligibleSlab = findEligibleSlab(itemCriteriaPayout.getPayoutSlabs(), purchasedValue);
35675 amit 924
            setSlabProgress(itemCriteriaPayout, eligibleSlab, purchasedValue);
36051 amit 925
            // For FIXED (per pc) payout, use per-criteria qty not base value
926
            int sellinValueForFixed = itemCriteriaPayout.getAmountType().equals(AmountType.FIXED) ? criteriaQty : purchasedValue;
35667 amit 927
            double finalPayout = calculateFinalPayout(eligibleSlab, itemCriteriaPayout.getAmountType(),
36051 amit 928
                    purchasedValue, sellinValueForFixed);
35394 amit 929
            qtyAmountModel.setFinalPayout(finalPayout);
930
        }
931
        return criteriaQtyAmountMap;
932
    }
933
 
934
    private Map<Integer, QtyAmountModel> getCriteriaQtyAmountModelMapForSelloutAndActivation(CreateOfferRequest createOfferRequest, int fofoId) {
935
        Map<Integer, Map<Integer, List<FofoOrderItem>>> criteriaPartnerwiseTertiary = offerRepository.getCriteriaWisePartnerTertiary(createOfferRequest, fofoId);
936
        Map<Integer, QtyAmountModel> qtyAmountMap;
937
        final Map<String, LocalDateTime> activatedImeisActivationDateMap;
938
        qtyAmountMap = new HashMap<>();
939
        if (createOfferRequest.getSchemeType().equals(OfferSchemeType.ACTIVATION)) {
940
            //All Serialnumbers for all eligible retailers
941
            List<String> serialNumbers = criteriaPartnerwiseTertiary.entrySet().stream().flatMap(x -> x.getValue().entrySet().stream().flatMap(foiList -> foiList.getValue().stream()))
942
                    .flatMap(y -> y.getFofoLineItems().stream()).filter(fli -> fli.getSerialNumber() != null)
943
                    .map(x -> x.getSerialNumber()).collect(Collectors.toList());
944
            if (serialNumbers.size() > 0) {
945
            /*if (imeisAllowedManually != null) {
946
                serialNumbers = serialNumbers.stream().filter(x -> imeisAllowedManually.contains(x)).collect(Collectors.toList());
947
            }*/
948
                activatedImeisActivationDateMap = activatedImeiRepository.selectBySerialNumbers(serialNumbers).stream()
949
                        .filter(x -> createOfferRequest.isWithinRange(x.getActivationTimestamp()))
950
                        .collect(Collectors.toMap(x -> x.getSerialNumber(), x -> x.getActivationTimestamp()));
951
            } else {
952
                activatedImeisActivationDateMap = null;
953
            }
954
        } else {
955
            activatedImeisActivationDateMap = null;
956
        }
957
 
958
        QtyAmountModel qtyAmountModel = null;
959
        if (createOfferRequest.isBaseCriteria()) {
35667 amit 960
            Map<Integer, List<FofoOrderItem>> baseCriteriaMap = criteriaPartnerwiseTertiary.get(0);
961
            List<FofoOrderItem> fofoOrderItems = baseCriteriaMap == null ? null : baseCriteriaMap.get(fofoId);
35394 amit 962
            int totalBaseQty = fofoOrderItems == null ? 0 : fofoOrderItems.stream().filter(x->createOfferRequest.isWithinRange(x.getCreateTimestamp())).collect(Collectors.summingInt(x -> (x.getQuantity())));
963
            int totalBaseValue = fofoOrderItems == null ? 0 : fofoOrderItems.stream().filter(x->createOfferRequest.isWithinRange(x.getCreateTimestamp())).mapToInt(x -> (Math.round(x.getDp())) * x.getQuantity()).sum();
964
            qtyAmountModel = new QtyAmountModel(totalBaseQty, totalBaseValue);
965
            if (createOfferRequest.getSchemeType().equals(OfferSchemeType.ACTIVATION)) {
966
                Map<Integer, Integer> inventoryItemValueMap = new HashMap<>();
35667 amit 967
                if (fofoOrderItems != null) {
968
                    for (FofoOrderItem fofoOrderItem : fofoOrderItems) {
969
                        fofoOrderItem.getFofoLineItems().stream().filter(x -> x.getSerialNumber() != null).forEach(
970
                                lineItem -> {
971
                                    if (activatedImeisActivationDateMap == null || activatedImeisActivationDateMap.containsKey(lineItem.getSerialNumber())) {
972
                                        inventoryItemValueMap.put(lineItem.getInventoryItemId(), (int) fofoOrderItem.getDp());
973
                                    }
35394 amit 974
                                }
35667 amit 975
                        );
976
                    }
35394 amit 977
                }
978
                qtyAmountModel.setActivationQty(inventoryItemValueMap.size());
979
                qtyAmountModel.setActivationAmount(inventoryItemValueMap.entrySet().stream().collect(Collectors.summingInt(x -> x.getValue())));
980
                qtyAmountMap.put(0, qtyAmountModel);
981
            }
982
        }
983
 
984
        //CriteriaPayoutWise
985
        for (ItemCriteriaPayout itemCriteriaPayout : createOfferRequest.getTargetSlabs().get(0).getItemCriteriaPayouts()) {
986
            int criteriaId = itemCriteriaPayout.getItemCriteria().getId();
987
            Map<Integer, List<FofoOrderItem>> ordersMap = criteriaPartnerwiseTertiary.get(criteriaId);
988
 
35667 amit 989
            QtyAmountModel criteriaQtyAmountModel = new QtyAmountModel(0, 0);
990
            qtyAmountMap.put(criteriaId, criteriaQtyAmountModel);
35394 amit 991
 
35667 amit 992
            if (ordersMap == null) continue;
35394 amit 993
 
35667 amit 994
            List<FofoOrderItem> fofoOrderItems = ordersMap.get(fofoId);
995
            if (fofoOrderItems == null || fofoOrderItems.isEmpty()) continue;
35394 amit 996
 
35673 amit 997
            int totalQty = fofoOrderItems.stream().filter(x -> createOfferRequest.isWithinRange(x.getCreateTimestamp())).collect(Collectors.summingInt(x -> (x.getQuantity())));
998
            int totalValue = fofoOrderItems.stream().filter(x -> createOfferRequest.isWithinRange(x.getCreateTimestamp())).collect(Collectors.summingInt(x -> Math.round(x.getDp()) * (x.getQuantity())));
35667 amit 999
            int eligibleQty = totalQty;
1000
            int eligibleValue = totalValue;
1001
            criteriaQtyAmountModel.setQty(totalQty);
1002
            criteriaQtyAmountModel.setAmount(totalValue);
35394 amit 1003
 
35667 amit 1004
            Map<FofoLineItem, Integer> lineItemValueMap = new HashMap<>();
1005
            if (createOfferRequest.getSchemeType().equals(OfferSchemeType.ACTIVATION)) {
1006
                for (FofoOrderItem fofoOrderItem : fofoOrderItems) {
1007
                    fofoOrderItem.getFofoLineItems().stream().filter(x -> x.getSerialNumber() != null).forEach(
1008
                            lineItem -> {
1009
                                if (activatedImeisActivationDateMap == null) {
1010
                                    lineItemValueMap.put(lineItem, (int) fofoOrderItem.getDp());
1011
                                } else if (activatedImeisActivationDateMap.containsKey(lineItem.getSerialNumber())) {
1012
                                    if (itemCriteriaPayout.isWithinRange(activatedImeisActivationDateMap.get(lineItem.getSerialNumber()))) {
1013
                                        lineItemValueMap.put(lineItem, (int) fofoOrderItem.getDp());
1014
                                    }
1015
                                }
1016
                            }
1017
                    );
35394 amit 1018
                }
35667 amit 1019
                eligibleQty = lineItemValueMap.size();
1020
                eligibleValue = lineItemValueMap.entrySet().stream().collect(Collectors.summingInt(x -> x.getValue()));
1021
                criteriaQtyAmountModel.setActivationQty(eligibleQty);
1022
                criteriaQtyAmountModel.setActivationAmount(eligibleValue);
1023
            }
35394 amit 1024
 
35667 amit 1025
            int eligibleBaseQty = eligibleQty;
1026
            int eligibleBaseValue = eligibleValue;
1027
            if (createOfferRequest.isBaseCriteria()) {
1028
                eligibleBaseQty = qtyAmountModel.getActivationQty();
1029
                eligibleBaseValue = (int) qtyAmountModel.getActivationAmount();
1030
            }
35394 amit 1031
 
35667 amit 1032
            int eligibleSale = eligibleBaseValue;
1033
            int eligibleCriteriaSale = eligibleValue;
1034
            int eligibleCriteriaSaleDp = eligibleValue;
35394 amit 1035
 
35667 amit 1036
            if (createOfferRequest.getTargetType().equals(AchievementType.QUANTITY)) {
1037
                eligibleSale = eligibleBaseQty;
1038
                eligibleCriteriaSale = eligibleQty;
35394 amit 1039
            }
1040
 
36051 amit 1041
            // For FIXED (per pc) payout, always use qty regardless of target type
1042
            int valueForFixed = itemCriteriaPayout.getAmountType().equals(AmountType.FIXED) ? eligibleQty : eligibleCriteriaSale;
1043
 
35667 amit 1044
            PayoutSlab eligibleSlab = findEligibleSlab(itemCriteriaPayout.getPayoutSlabs(), eligibleSale);
35675 amit 1045
            setSlabProgress(itemCriteriaPayout, eligibleSlab, eligibleSale);
35667 amit 1046
            double finalPayout = calculateFinalPayout(eligibleSlab, itemCriteriaPayout.getAmountType(),
36051 amit 1047
                    eligibleCriteriaSaleDp, valueForFixed);
35667 amit 1048
            if (eligibleSlab != null) {
1049
                LOGGER.info("Eligible Slab {}", eligibleSlab);
1050
            }
1051
            criteriaQtyAmountModel.setFinalPayout(finalPayout);
1052
            LOGGER.info("Final Payout - {}", finalPayout);
35394 amit 1053
        }
1054
        return qtyAmountMap;
1055
    }
1056
 
31920 amit.gupta 1057
    @Override
1058
    public void processActivationtOffer(CreateOfferRequest createOfferRequest) throws ProfitMandiBusinessException {
1059
        List<OfferPayout> offerPayouts = offerPayoutRepository.selectAllByOfferId(createOfferRequest.getId());
1060
        List<ItemCriteriaPayout> itemCriteriaPayouts = createOfferRequest.getTargetSlabs().get(0).getItemCriteriaPayouts();
1061
        Map<Integer, ItemCriteriaPayout> itemCriteriaPayoutMap = itemCriteriaPayouts.stream().collect(Collectors.toMap(x -> x.getItemCriteria().getId(), x -> x));
31923 amit.gupta 1062
        LOGGER.info("itemCriteriaPayoutMap {}", itemCriteriaPayoutMap);
1063
        LOGGER.info("offerPayouts {}", offerPayouts);
31924 amit.gupta 1064
        Map<Integer, Map<Integer, Double>> fixedSlabCriteriaPartnerMap = offerPayouts.stream().filter(x -> itemCriteriaPayoutMap.get((int) x.getCriteriaId()).getAmountType().equals(AmountType.SLAB_FIXED))
31920 amit.gupta 1065
                .collect(Collectors.groupingBy(x -> (int) x.getCriteriaId(), Collectors.groupingBy(x -> (int) x.getFofoId(), Collectors.summingDouble(x -> x.getSlabAmount()))));
1066
 
1067
 
1068
        Map<String, Double> serialNumberPaid = offerPayouts.stream().filter(x -> x.getRejectTimestamp() == null).collect(Collectors.groupingBy(x -> x.getSerialNumber(), Collectors.summingDouble(x -> x.getSlabAmount())));
1069
        Map<Integer, Map<Integer, List<FofoOrderItem>>> criteriaPartnerwiseTertiary = offerRepository.getCriteriaWisePartnerTertiary(createOfferRequest);
1070
 
33087 amit.gupta 1071
        Map<String, AgeingSummaryModel> ageingSummaryModelsMap = null;
33662 amit.gupta 1072
        final Map<String, LocalDateTime> activatedImeisActivationDateMap;
34217 amit.gupta 1073
        //Find Only eligible imeis if any
1074
        List<String> imeisAllowedManually = offerEligibleImeiRepository.selectEligibleImeisByOfferId(createOfferRequest.getId());
1075
 
31920 amit.gupta 1076
        if (createOfferRequest.getSchemeType().equals(OfferSchemeType.ACTIVATION)) {
1077
            //All Serialnumbers for all eligible retailers
1078
            List<String> serialNumbers = criteriaPartnerwiseTertiary.entrySet().stream().flatMap(x -> x.getValue().entrySet().stream().flatMap(foiList -> foiList.getValue().stream()))
1079
                    .flatMap(y -> y.getFofoLineItems().stream()).filter(fli -> fli.getSerialNumber() != null)
1080
                    .map(x -> x.getSerialNumber()).collect(Collectors.toList());
1081
            if (serialNumbers.size() > 0) {
34217 amit.gupta 1082
                if (imeisAllowedManually != null) {
1083
                    serialNumbers = serialNumbers.stream().filter(x -> imeisAllowedManually.contains(x)).collect(Collectors.toList());
1084
                }
33662 amit.gupta 1085
                activatedImeisActivationDateMap = activatedImeiRepository.selectBySerialNumbers(serialNumbers).stream()
31920 amit.gupta 1086
                        .filter(x -> createOfferRequest.isWithinRange(x.getActivationTimestamp()))
33441 amit.gupta 1087
                        .collect(Collectors.toMap(x -> x.getSerialNumber(), x -> x.getActivationTimestamp()));
33613 amit.gupta 1088
                ageingSummaryModelsMap = warehouseInventoryItemRepository.findStockAgeingByFofoIdSerialNumbers(0, serialNumbers).stream().collect(Collectors.toMap(x -> x.getSerialNumber(), x -> x, (u, v) -> v));
31920 amit.gupta 1089
            } else {
33662 amit.gupta 1090
                activatedImeisActivationDateMap = null;
31920 amit.gupta 1091
            }
1092
        } else {
33662 amit.gupta 1093
            activatedImeisActivationDateMap = null;
31920 amit.gupta 1094
        }
1095
 
1096
        Map<Integer, Integer> userBaseQtyMap = new HashMap<>();
1097
        Map<Integer, Integer> userBaseValueMap = new HashMap<>();
1098
        Map<Integer, Integer> eligibleBaseQtyMap = new HashMap<>();
1099
        Map<Integer, Integer> eligibleBaseValueMap = new HashMap<>();
1100
 
1101
        if (createOfferRequest.isBaseCriteria()) {
1102
            Map<Integer, List<FofoOrderItem>> foiMap = criteriaPartnerwiseTertiary.get(0);
1103
            for (Map.Entry<Integer, List<FofoOrderItem>> orderEntry : foiMap.entrySet()) {
1104
                int fofoId = orderEntry.getKey();
1105
                List<FofoOrderItem> fofoOrderItems = orderEntry.getValue();
1106
                int totalBaseQty = fofoOrderItems.stream().collect(Collectors.summingInt(x -> (x.getQuantity())));
1107
                int totalBaseValue = fofoOrderItems.stream().collect(Collectors.summingInt(x -> (Math.round(x.getDp())) * x.getQuantity()));
1108
                userBaseQtyMap.put(fofoId, totalBaseQty);
1109
                userBaseValueMap.put(fofoId, totalBaseValue);
1110
                if (createOfferRequest.getSchemeType().equals(OfferSchemeType.ACTIVATION)) {
1111
                    Map<Integer, Integer> inventoryItemValueMap = new HashMap<>();
1112
                    for (FofoOrderItem fofoOrderItem : fofoOrderItems) {
1113
                        fofoOrderItem.getFofoLineItems().stream().filter(x -> x.getSerialNumber() != null).forEach(
1114
                                lineItem -> {
33662 amit.gupta 1115
                                    if (activatedImeisActivationDateMap == null || activatedImeisActivationDateMap.containsKey(lineItem.getSerialNumber())) {
31920 amit.gupta 1116
                                        inventoryItemValueMap.put(lineItem.getInventoryItemId(), (int) fofoOrderItem.getDp());
1117
                                    }
1118
                                }
1119
                        );
1120
                    }
1121
                    eligibleBaseQtyMap.put(fofoId, inventoryItemValueMap.size());
1122
                    eligibleBaseValueMap.put(fofoId, inventoryItemValueMap.entrySet().stream().collect(Collectors.summingInt(x -> x.getValue())));
1123
                } else {
1124
                    eligibleBaseQtyMap.put(fofoId, totalBaseQty);
1125
                    eligibleBaseValueMap.put(fofoId, totalBaseValue);
1126
 
1127
                }
1128
 
1129
            }
1130
        }
1131
 
1132
        //As of now eligible sale is considered to be without special criteria like brand/
33441 amit.gupta 1133
        //CriteriaPayoutWise
31920 amit.gupta 1134
        for (ItemCriteriaPayout itemCriteriaPayout : createOfferRequest.getTargetSlabs().get(0).getItemCriteriaPayouts()) {
1135
            int criteriaId = itemCriteriaPayout.getItemCriteria().getId();
1136
            Map<Integer, List<FofoOrderItem>> ordersMap = criteriaPartnerwiseTertiary.get(criteriaId);
33441 amit.gupta 1137
            //Partywise iteration
31920 amit.gupta 1138
            for (Map.Entry<Integer, List<FofoOrderItem>> orderEntry : ordersMap.entrySet()) {
31992 amit.gupta 1139
                double totalRolloutAmount = 0;
31920 amit.gupta 1140
                int fofoId = orderEntry.getKey();
1141
                List<FofoOrderItem> fofoOrderItems = orderEntry.getValue();
1142
                OfferRowModel offerRowModel = new OfferRowModel();
1143
                int totalQty = fofoOrderItems.stream().collect(Collectors.summingInt(x -> (x.getQuantity())));
1144
                int totalValue = fofoOrderItems.stream().collect(Collectors.summingInt(x -> Math.round(x.getDp()) * (x.getQuantity())));
1145
                int eligibleQty = totalQty;
1146
                int eligibleValue = totalValue;
1147
                Map<FofoLineItem, Integer> lineItemValueMap = new HashMap<>();
1148
                if (createOfferRequest.getSchemeType().equals(OfferSchemeType.ACTIVATION)) {
1149
                    for (FofoOrderItem fofoOrderItem : fofoOrderItems) {
1150
                        fofoOrderItem.getFofoLineItems().stream().filter(x -> x.getSerialNumber() != null).forEach(
1151
                                lineItem -> {
33662 amit.gupta 1152
                                    if (activatedImeisActivationDateMap == null) {
31920 amit.gupta 1153
                                        lineItemValueMap.put(lineItem, (int) fofoOrderItem.getDp());
33441 amit.gupta 1154
 
33662 amit.gupta 1155
                                    } else if (activatedImeisActivationDateMap.containsKey(lineItem.getSerialNumber())) {
1156
                                        if (itemCriteriaPayout.isWithinRange(activatedImeisActivationDateMap.get(lineItem.getSerialNumber()))) {
33441 amit.gupta 1157
                                            lineItemValueMap.put(lineItem, (int) fofoOrderItem.getDp());
1158
                                        }
31920 amit.gupta 1159
                                    }
33441 amit.gupta 1160
 
31920 amit.gupta 1161
                                }
1162
                        );
1163
                    }
1164
                    eligibleQty = lineItemValueMap.size();
1165
                    eligibleValue = lineItemValueMap.entrySet().stream().collect(Collectors.summingInt(x -> x.getValue()));
1166
                    offerRowModel.setEligibleImeis(lineItemValueMap.keySet().stream().map(x -> x.getSerialNumber()).collect(Collectors.toList()));
1167
                }
1168
 
1169
                int totalBaseQty = totalQty;
1170
                int totalBaseValue = totalValue;
1171
                int eligibleBaseQty = eligibleQty;
1172
                int eligibleBaseValue = eligibleValue;
1173
                if (createOfferRequest.isBaseCriteria()) {
1174
                    totalBaseQty = userBaseQtyMap.get(fofoId) == null ? 0 : userBaseQtyMap.get(fofoId);
1175
                    totalBaseValue = userBaseValueMap.get(fofoId) == null ? 0 : userBaseValueMap.get(fofoId);
1176
                    eligibleBaseQty = eligibleBaseQtyMap.get(fofoId) == null ? 0 : eligibleBaseQtyMap.get(fofoId);
1177
                    eligibleBaseValue = eligibleBaseValueMap.get(fofoId) == null ? 0 : eligibleBaseValueMap.get(fofoId);
1178
                }
1179
 
1180
 
1181
                int totalSale = totalBaseValue;
1182
                int eligibleSale = eligibleBaseValue;
1183
                int eligibleCriteriaSale = eligibleValue;
1184
                int eligibleCriteriaSaleDp = eligibleValue;
1185
 
1186
                if (createOfferRequest.getTargetType().equals(AchievementType.QUANTITY)) {
1187
                    totalSale = totalBaseQty;
1188
                    eligibleSale = eligibleBaseQty;
1189
                    eligibleCriteriaSale = eligibleQty;
1190
                }
1191
 
1192
                offerRowModel.setTotalSale(totalSale);
1193
                offerRowModel.setEligibleSale(eligibleSale);
1194
                float eligiblePayoutValue = 0;
33662 amit.gupta 1195
                float previousPayoutValue = 0;
32345 amit.gupta 1196
                double finalPayout;
31920 amit.gupta 1197
                for (PayoutSlab payoutSlab : itemCriteriaPayout.getPayoutSlabs()) {
1198
                    if (payoutSlab.getOnwardsAmount() <= eligibleSale) {
32039 amit.gupta 1199
                        LOGGER.info("Eligible Sale {}", eligibleSale);
31920 amit.gupta 1200
                        offerRowModel.setPayoutTargetAchieved(payoutSlab.getOnwardsAmount());
1201
                        eligiblePayoutValue = payoutSlab.getPayoutAmount();
33662 amit.gupta 1202
                        previousPayoutValue = Math.min(eligiblePayoutValue, previousPayoutValue);
31920 amit.gupta 1203
                        offerRowModel.setPayoutValue(eligiblePayoutValue);
33662 amit.gupta 1204
                    } else {
1205
                        break;
31920 amit.gupta 1206
                    }
1207
                }
1208
                if (AmountType.PERCENTAGE.equals(itemCriteriaPayout.getAmountType())) {
1209
                    finalPayout = (eligiblePayoutValue * eligibleCriteriaSaleDp) / 100;
1210
                } else if (AmountType.FIXED.equals(itemCriteriaPayout.getAmountType())) {
36051 amit 1211
                    // FIXED = per piece, always use qty regardless of target type
1212
                    finalPayout = eligiblePayoutValue * eligibleQty;
31920 amit.gupta 1213
                } else {
32039 amit.gupta 1214
                    Map<Integer, Double> fofoCriteriaMap = fixedSlabCriteriaPartnerMap.get(criteriaId);
1215
                    LOGGER.info("fofoCriteriaMap {}", fofoCriteriaMap);
31920 amit.gupta 1216
                    finalPayout = eligiblePayoutValue;
1217
                    if (fofoCriteriaMap != null) {
1218
                        if (fofoCriteriaMap.containsKey(fofoId)) {
33662 amit.gupta 1219
                            //double totalPayout = fofoCriteriaMap.get(fofoId);
1220
                            finalPayout = eligiblePayoutValue - previousPayoutValue;
32039 amit.gupta 1221
                            if (Math.abs(finalPayout) < Utils.DOUBLE_EPSILON) {
31920 amit.gupta 1222
                                finalPayout = 0;
32039 amit.gupta 1223
                            }
31920 amit.gupta 1224
                        }
1225
                    }
1226
                }
1227
 
32039 amit.gupta 1228
                LOGGER.info("Final Payout - {}", finalPayout);
1229
 
31920 amit.gupta 1230
                if (finalPayout > 0) {
1231
                    List<Integer> inventoryItemIds = lineItemValueMap.keySet().stream().map(x -> x.getInventoryItemId()).collect(Collectors.toList());
33662 amit.gupta 1232
                    int totalDpValue = lineItemValueMap.values().stream().collect(Collectors.summingInt(x -> x));
1233
                    LOGGER.info("Total DP Value {}", totalDpValue);
31920 amit.gupta 1234
                    Map<Integer, InventoryItem> inventoryItemsMap = inventoryItemRepository.selectAllByIds(inventoryItemIds).stream().collect(Collectors.toMap(x -> x.getId(), x -> x));
1235
                    for (Map.Entry<FofoLineItem, Integer> lineItemValueEntry : lineItemValueMap.entrySet()) {
33087 amit.gupta 1236
                        FofoLineItem fofoLineItem = lineItemValueEntry.getKey();
31920 amit.gupta 1237
                        double amount = 0;
1238
                        if (AmountType.SLAB_FIXED.equals(itemCriteriaPayout.getAmountType())) {
32039 amit.gupta 1239
                            amount = (eligiblePayoutValue * lineItemValueEntry.getValue()) / totalDpValue;
31920 amit.gupta 1240
                        } else {
33662 amit.gupta 1241
                            if (ageingSummaryModelsMap.containsKey(fofoLineItem.getSerialNumber())) {
35394 amit 1242
                                if (ageingSummaryModelsMap.get(fofoLineItem.getSerialNumber()).isAgedAbove(STOCK_AGEING_THRESHOLD_DAYS)) {
33662 amit.gupta 1243
                                    continue;
1244
                                }
1245
                            }
31920 amit.gupta 1246
                            amount = eligiblePayoutValue;
1247
                        }
33662 amit.gupta 1248
                        if (serialNumberPaid.containsKey(fofoLineItem.getSerialNumber())) {
1249
                            amount = amount - serialNumberPaid.get(fofoLineItem.getSerialNumber());
1250
                        }
32039 amit.gupta 1251
                        LOGGER.info("Amount - {}", amount);
31920 amit.gupta 1252
                        //ignore reasonably small
1253
                        if (amount < Utils.DOUBLE_EPSILON) continue;
1254
                        AmountModel amountModel = new AmountModel();
1255
                        amountModel.setAmountType(itemCriteriaPayout.getAmountType());
1256
                        amountModel.setAmount(amount);
32021 amit.gupta 1257
                        amountModel.setDiscount(createOfferRequest.isDiscount());
33087 amit.gupta 1258
                        InventoryPayoutModel inventoryPayoutModel = priceCircularService.getPayouts(inventoryItemsMap.get(fofoLineItem.getInventoryItemId()));
31920 amit.gupta 1259
                        double rolloutAmount = inventoryPayoutModel.getRolloutAmount(amountModel);
1260
                        totalRolloutAmount += rolloutAmount;
1261
 
33087 amit.gupta 1262
                        OfferPayout offerPayout = new OfferPayout(fofoId, createOfferRequest.getId(), criteriaId, amount, fofoLineItem.getSerialNumber(), rolloutAmount, SchemePayoutStatus.CREDITED, createOfferRequest.getDescription(), LocalDateTime.now());
33459 amit.gupta 1263
                        offerPayout.setInventoryItemId(fofoLineItem.getInventoryItemId());
31920 amit.gupta 1264
                        offerPayoutRepository.persist(offerPayout);
1265
                    }
32039 amit.gupta 1266
                    walletService.addAmountToWallet((int) fofoId, createOfferRequest.getId(), WalletReferenceType.ADDITIONAL_SCHEME, createOfferRequest.getDescription(), (float) totalRolloutAmount, LocalDateTime.now());
31920 amit.gupta 1267
                }
1268
            }
1269
        }
1270
        Offer offer = offerRepository.selectById(createOfferRequest.getId());
1271
        offer.setProcessedTimestamp(LocalDateTime.now());
1272
    }
1273
 
1274
    @Override
36305 amit 1275
    @Transactional(readOnly = true)
1276
    public List<OfferPartnerPayoutData> calculateOfferPayouts(CreateOfferRequest createOfferRequest) throws ProfitMandiBusinessException {
1277
        List<OfferPartnerPayoutData> result = new ArrayList<>();
1278
 
1279
        List<OfferPayout> offerPayouts = offerPayoutRepository.selectAllByOfferId(createOfferRequest.getId());
1280
        List<ItemCriteriaPayout> itemCriteriaPayouts = createOfferRequest.getTargetSlabs().get(0).getItemCriteriaPayouts();
1281
        Map<Integer, ItemCriteriaPayout> itemCriteriaPayoutMap = itemCriteriaPayouts.stream().collect(Collectors.toMap(x -> x.getItemCriteria().getId(), x -> x));
1282
 
1283
        Map<Integer, Map<Integer, Double>> fixedSlabCriteriaPartnerMap = offerPayouts.stream()
1284
                .filter(x -> itemCriteriaPayoutMap.containsKey((int) x.getCriteriaId()) &&
1285
                        itemCriteriaPayoutMap.get((int) x.getCriteriaId()).getAmountType().equals(AmountType.SLAB_FIXED))
1286
                .collect(Collectors.groupingBy(x -> (int) x.getCriteriaId(),
1287
                        Collectors.groupingBy(x -> (int) x.getFofoId(), Collectors.summingDouble(x -> x.getSlabAmount()))));
1288
 
1289
        Map<String, Double> serialNumberPaid = offerPayouts.stream()
1290
                .filter(x -> x.getRejectTimestamp() == null)
1291
                .collect(Collectors.groupingBy(x -> x.getSerialNumber(), Collectors.summingDouble(x -> x.getSlabAmount())));
1292
 
1293
        Map<Integer, Map<Integer, List<FofoOrderItem>>> criteriaPartnerwiseTertiary = offerRepository.getCriteriaWisePartnerTertiary(createOfferRequest);
1294
 
1295
        Map<String, AgeingSummaryModel> ageingSummaryModelsMap = null;
1296
        final Map<String, LocalDateTime> activatedImeisActivationDateMap;
1297
        List<String> imeisAllowedManually = offerEligibleImeiRepository.selectEligibleImeisByOfferId(createOfferRequest.getId());
1298
 
1299
        if (createOfferRequest.getSchemeType().equals(OfferSchemeType.ACTIVATION)) {
1300
            List<String> serialNumbers = criteriaPartnerwiseTertiary.entrySet().stream()
1301
                    .flatMap(x -> x.getValue().entrySet().stream().flatMap(foiList -> foiList.getValue().stream()))
1302
                    .flatMap(y -> y.getFofoLineItems().stream()).filter(fli -> fli.getSerialNumber() != null)
1303
                    .map(x -> x.getSerialNumber()).collect(Collectors.toList());
1304
            if (serialNumbers.size() > 0) {
1305
                if (imeisAllowedManually != null) {
1306
                    serialNumbers = serialNumbers.stream().filter(x -> imeisAllowedManually.contains(x)).collect(Collectors.toList());
1307
                }
1308
                activatedImeisActivationDateMap = activatedImeiRepository.selectBySerialNumbers(serialNumbers).stream()
1309
                        .filter(x -> createOfferRequest.isWithinRange(x.getActivationTimestamp()))
1310
                        .collect(Collectors.toMap(x -> x.getSerialNumber(), x -> x.getActivationTimestamp()));
1311
                ageingSummaryModelsMap = warehouseInventoryItemRepository.findStockAgeingByFofoIdSerialNumbers(0, serialNumbers)
1312
                        .stream().collect(Collectors.toMap(x -> x.getSerialNumber(), x -> x, (u, v) -> v));
1313
            } else {
1314
                activatedImeisActivationDateMap = null;
1315
            }
1316
        } else {
1317
            activatedImeisActivationDateMap = null;
1318
        }
1319
 
1320
        Map<Integer, Integer> userBaseQtyMap = new HashMap<>();
1321
        Map<Integer, Integer> userBaseValueMap = new HashMap<>();
1322
        Map<Integer, Integer> calcEligibleBaseQtyMap = new HashMap<>();
1323
        Map<Integer, Integer> calcEligibleBaseValueMap = new HashMap<>();
1324
 
1325
        if (createOfferRequest.isBaseCriteria()) {
1326
            Map<Integer, List<FofoOrderItem>> foiMap = criteriaPartnerwiseTertiary.get(0);
1327
            if (foiMap != null) {
1328
                for (Map.Entry<Integer, List<FofoOrderItem>> orderEntry : foiMap.entrySet()) {
1329
                    int fofoId = orderEntry.getKey();
1330
                    List<FofoOrderItem> fofoOrderItems = orderEntry.getValue();
1331
                    int totalBaseQty = fofoOrderItems.stream().collect(Collectors.summingInt(x -> (x.getQuantity())));
1332
                    int totalBaseValue = fofoOrderItems.stream().collect(Collectors.summingInt(x -> (Math.round(x.getDp())) * x.getQuantity()));
1333
                    userBaseQtyMap.put(fofoId, totalBaseQty);
1334
                    userBaseValueMap.put(fofoId, totalBaseValue);
1335
                    if (createOfferRequest.getSchemeType().equals(OfferSchemeType.ACTIVATION)) {
1336
                        Map<Integer, Integer> inventoryItemValueMap = new HashMap<>();
1337
                        for (FofoOrderItem fofoOrderItem : fofoOrderItems) {
1338
                            fofoOrderItem.getFofoLineItems().stream().filter(x -> x.getSerialNumber() != null).forEach(
1339
                                    lineItem -> {
1340
                                        if (activatedImeisActivationDateMap == null || activatedImeisActivationDateMap.containsKey(lineItem.getSerialNumber())) {
1341
                                            inventoryItemValueMap.put(lineItem.getInventoryItemId(), (int) fofoOrderItem.getDp());
1342
                                        }
1343
                                    }
1344
                            );
1345
                        }
1346
                        calcEligibleBaseQtyMap.put(fofoId, inventoryItemValueMap.size());
1347
                        calcEligibleBaseValueMap.put(fofoId, inventoryItemValueMap.entrySet().stream().collect(Collectors.summingInt(x -> x.getValue())));
1348
                    } else {
1349
                        calcEligibleBaseQtyMap.put(fofoId, totalBaseQty);
1350
                        calcEligibleBaseValueMap.put(fofoId, totalBaseValue);
1351
                    }
1352
                }
1353
            }
1354
        }
1355
 
1356
        for (ItemCriteriaPayout itemCriteriaPayout : createOfferRequest.getTargetSlabs().get(0).getItemCriteriaPayouts()) {
1357
            int criteriaId = itemCriteriaPayout.getItemCriteria().getId();
1358
            Map<Integer, List<FofoOrderItem>> ordersMap = criteriaPartnerwiseTertiary.get(criteriaId);
1359
            if (ordersMap == null) continue;
1360
 
1361
            for (Map.Entry<Integer, List<FofoOrderItem>> orderEntry : ordersMap.entrySet()) {
1362
                int fofoId = orderEntry.getKey();
1363
                List<FofoOrderItem> fofoOrderItems = orderEntry.getValue();
1364
                int totalQty = fofoOrderItems.stream().collect(Collectors.summingInt(x -> (x.getQuantity())));
1365
                int totalValue = fofoOrderItems.stream().collect(Collectors.summingInt(x -> Math.round(x.getDp()) * (x.getQuantity())));
1366
                int eligibleQty = totalQty;
1367
                int eligibleValue = totalValue;
1368
                Map<FofoLineItem, Integer> lineItemValueMap = new HashMap<>();
1369
                if (createOfferRequest.getSchemeType().equals(OfferSchemeType.ACTIVATION)) {
1370
                    for (FofoOrderItem fofoOrderItem : fofoOrderItems) {
1371
                        fofoOrderItem.getFofoLineItems().stream().filter(x -> x.getSerialNumber() != null).forEach(
1372
                                lineItem -> {
1373
                                    if (activatedImeisActivationDateMap == null) {
1374
                                        lineItemValueMap.put(lineItem, (int) fofoOrderItem.getDp());
1375
                                    } else if (activatedImeisActivationDateMap.containsKey(lineItem.getSerialNumber())) {
1376
                                        if (itemCriteriaPayout.isWithinRange(activatedImeisActivationDateMap.get(lineItem.getSerialNumber()))) {
1377
                                            lineItemValueMap.put(lineItem, (int) fofoOrderItem.getDp());
1378
                                        }
1379
                                    }
1380
                                }
1381
                        );
1382
                    }
1383
                    eligibleQty = lineItemValueMap.size();
1384
                    eligibleValue = lineItemValueMap.entrySet().stream().collect(Collectors.summingInt(x -> x.getValue()));
1385
                }
1386
 
1387
                int eligibleBaseQty = eligibleQty;
1388
                int eligibleBaseValue = eligibleValue;
1389
                if (createOfferRequest.isBaseCriteria()) {
1390
                    eligibleBaseQty = calcEligibleBaseQtyMap.get(fofoId) == null ? 0 : calcEligibleBaseQtyMap.get(fofoId);
1391
                    eligibleBaseValue = calcEligibleBaseValueMap.get(fofoId) == null ? 0 : calcEligibleBaseValueMap.get(fofoId);
1392
                }
1393
 
1394
                int eligibleSale = eligibleBaseValue;
1395
                int eligibleCriteriaSaleDp = eligibleValue;
1396
                if (createOfferRequest.getTargetType().equals(AchievementType.QUANTITY)) {
1397
                    eligibleSale = eligibleBaseQty;
1398
                }
1399
 
1400
                float eligiblePayoutValue = 0;
1401
                float previousPayoutValue = 0;
1402
                double finalPayout;
1403
                for (PayoutSlab payoutSlab : itemCriteriaPayout.getPayoutSlabs()) {
1404
                    if (payoutSlab.getOnwardsAmount() <= eligibleSale) {
1405
                        eligiblePayoutValue = payoutSlab.getPayoutAmount();
1406
                        previousPayoutValue = Math.min(eligiblePayoutValue, previousPayoutValue);
1407
                    } else {
1408
                        break;
1409
                    }
1410
                }
1411
                if (AmountType.PERCENTAGE.equals(itemCriteriaPayout.getAmountType())) {
1412
                    finalPayout = (eligiblePayoutValue * eligibleCriteriaSaleDp) / 100;
1413
                } else if (AmountType.FIXED.equals(itemCriteriaPayout.getAmountType())) {
1414
                    finalPayout = eligiblePayoutValue * eligibleQty;
1415
                } else {
1416
                    Map<Integer, Double> fofoCriteriaMap = fixedSlabCriteriaPartnerMap.get(criteriaId);
1417
                    finalPayout = eligiblePayoutValue;
1418
                    if (fofoCriteriaMap != null && fofoCriteriaMap.containsKey(fofoId)) {
1419
                        finalPayout = eligiblePayoutValue - previousPayoutValue;
1420
                        if (Math.abs(finalPayout) < Utils.DOUBLE_EPSILON) {
1421
                            finalPayout = 0;
1422
                        }
1423
                    }
1424
                }
1425
 
1426
                if (finalPayout > 0) {
1427
                    result.add(new OfferPartnerPayoutData(
1428
                            fofoId, criteriaId, finalPayout, eligiblePayoutValue,
1429
                            lineItemValueMap, itemCriteriaPayout, serialNumberPaid,
1430
                            ageingSummaryModelsMap, createOfferRequest.isDiscount()));
1431
                }
1432
            }
1433
        }
1434
 
1435
        return result;
1436
    }
1437
 
1438
    @Override
31920 amit.gupta 1439
    public void processSellin(CreateOfferRequest createOfferRequest) throws Exception {
1440
 
1441
        //List<OfferRowModel> offerRowModels = new ArrayList<>();
1442
        List<OfferPayout> offerPayouts = offerPayoutRepository.selectAllByOfferId(createOfferRequest.getId());
32345 amit.gupta 1443
        Map<String, Double> serialNumberPaid = offerPayouts.stream().filter(x -> x.getRejectTimestamp() == null).collect(Collectors.groupingBy(x -> x.getSerialNumber(), Collectors.summingDouble(x -> x.getSlabAmount())));
34072 ranu 1444
        LOGGER.info("serialNumberPaid {}", serialNumberPaid);
32345 amit.gupta 1445
        List<ItemCriteriaPayout> itemCriteriaPayouts = createOfferRequest.getTargetSlabs().get(0).getItemCriteriaPayouts();
1446
        Map<Integer, ItemCriteriaPayout> itemCriteriaPayoutMap = itemCriteriaPayouts.stream().collect(Collectors.toMap(x -> x.getItemCriteria().getId(), x -> x));
1447
        Map<Integer, Map<Integer, Double>> fixedSlabCriteriaPartnerMap = offerPayouts.stream().filter(x -> itemCriteriaPayoutMap.get((int) x.getCriteriaId()).getAmountType().equals(AmountType.SLAB_FIXED))
1448
                .collect(Collectors.groupingBy(x -> (int) x.getCriteriaId(), Collectors.groupingBy(x -> (int) x.getFofoId(), Collectors.summingDouble(x -> x.getSlabAmount()))));
31920 amit.gupta 1449
        Set<Long> fofoIds = offerPayouts.stream().map(x -> x.getFofoId()).collect(Collectors.toSet());
1450
 
1451
        Map<Integer, Map<Integer, List<Order>>> criteriaOrdersMap = offerRepository.getPartnerWiseSellin(createOfferRequest, true);
1452
 
32345 amit.gupta 1453
 
31920 amit.gupta 1454
        Map<Integer, List<Order>> userBaseCriteriaOrdersMap = null;
1455
        if (criteriaOrdersMap.get(0) != null && criteriaOrdersMap.get(0).size() > 0) {
1456
            userBaseCriteriaOrdersMap = criteriaOrdersMap.get(0).entrySet().stream()
1457
                    .filter(x -> !fofoIds.contains(x.getKey())).collect(Collectors.toMap(x -> x.getKey(), x -> x.getValue()));
1458
        }
1459
 
32345 amit.gupta 1460
 
31920 amit.gupta 1461
        Map<Integer, Integer> userBaseQtyMap = null;
1462
        Map<Integer, Integer> userBaseValueMap = null;
1463
        if (userBaseCriteriaOrdersMap != null) {
1464
            userBaseQtyMap = new HashMap<>();
1465
            userBaseValueMap = new HashMap<>();
1466
            for (Map.Entry<Integer, List<Order>> orderEntry : userBaseCriteriaOrdersMap.entrySet()) {
1467
                int fofoId = orderEntry.getKey();
1468
                List<Order> orders = orderEntry.getValue();
1469
                int totalBaseQty = orders.stream().collect(Collectors.summingInt(x -> (x.getLineItem().getQuantity() - x.getLineItem().getReturnQty())));
1470
                int totalBaseValue = orders.stream().collect(Collectors.summingInt(x ->
1471
                        Math.round(x.getLineItem().getUnitPrice() * (x.getLineItem().getQuantity() - x.getLineItem().getReturnQty()))
1472
                ));
1473
                userBaseQtyMap.put(fofoId, totalBaseQty);
1474
                userBaseValueMap.put(fofoId, totalBaseValue);
1475
            }
1476
        }
1477
        LOGGER.info("Base Qty Map - {}", userBaseQtyMap);
1478
        LOGGER.info("Base Value Map - {}", userBaseValueMap);
1479
 
1480
        LOGGER.info("Processing sellin");
1481
        List<OfferPayout> offerPayoutsNew = new ArrayList<>();
1482
        for (ItemCriteriaPayout itemCriteriaPayout : createOfferRequest.getTargetSlabs().get(0).getItemCriteriaPayouts()) {
1483
            int criteriaId = itemCriteriaPayout.getItemCriteria().getId();
1484
            Map<Integer, List<Order>> ordersMap = criteriaOrdersMap.get(criteriaId).entrySet().stream()
1485
                    .filter(x -> !fofoIds.contains(x.getKey())).collect(Collectors.toMap(x -> x.getKey(), x -> x.getValue()));
1486
            for (Map.Entry<Integer, List<Order>> orderEntry : ordersMap.entrySet()) {
1487
                int fofoId = orderEntry.getKey();
1488
                //CustomRetailer retailer = retailerService.getAllFofoRetailers().get(fofoId);
1489
                List<Order> orders = orderEntry.getValue();
32345 amit.gupta 1490
                //Set<String> returnedSerialNumbers = orders.stream().filter(x -> x.getSerialNumber() != null).flatMap(x -> x.getReturnedImeis().stream()).collect(Collectors.toSet());
31920 amit.gupta 1491
                int totalQty = orders.stream().collect(Collectors.summingInt(x -> (x.getLineItem().getQuantity() - x.getLineItem().getReturnQty())));
1492
                int totalValue = orders.stream().collect(Collectors.summingInt(x -> Math.round(x.getLineItem().
1493
                        getUnitPrice() * (x.getLineItem().getQuantity() - x.getLineItem().getReturnQty()))));
1494
                int totalBaseQty = totalQty;
1495
                int totalBaseValue = totalValue;
1496
                if (userBaseCriteriaOrdersMap != null) {
1497
                    if (userBaseQtyMap.containsKey(fofoId)) {
1498
                        totalBaseQty = userBaseQtyMap.get(fofoId);
1499
                        totalBaseValue = userBaseValueMap.get(fofoId);
1500
                    } else {
1501
                        continue;
1502
                    }
1503
                }
1504
 
1505
                int purchasedValue;
1506
                if (createOfferRequest.getTargetType().equals(AchievementType.VALUE)) {
1507
                    purchasedValue = totalBaseValue;
1508
                } else {
1509
                    purchasedValue = totalBaseQty;
1510
                }
1511
 
33695 amit.gupta 1512
                PayoutSlab eligibleSlab = null;
33662 amit.gupta 1513
 
1514
                for (PayoutSlab payoutSlab : itemCriteriaPayout.getPayoutSlabs()) {
1515
                    if (payoutSlab.getOnwardsAmount() <= purchasedValue) {
1516
                        eligibleSlab = payoutSlab;
1517
                    } else {
1518
                        break;
1519
                    }
1520
                }
33695 amit.gupta 1521
                if (eligibleSlab == null) continue;
31920 amit.gupta 1522
                List<Integer> orderIds = orders.stream().map(x -> x.getId()).collect(Collectors.toList());
1523
                Map<Integer, LineItem> lineItemMap = orders.stream().collect(Collectors.toMap(x -> x.getLineItem().getId(), x -> x.getLineItem()));
1524
                List<WarehouseScan> warehouseScans = warehouseScanRepository.selectAllByOrderIds(orderIds);
32540 amit.gupta 1525
                LOGGER.info("Warehosue scans --> {}", warehouseScans);
32345 amit.gupta 1526
                List<Integer> warehouseInventoryItemIds = warehouseScans.stream().collect(Collectors.groupingBy(x -> x.getInventoryItemId())).entrySet()
31920 amit.gupta 1527
                        .stream().filter(x -> x.getValue().size() == 1).map(x -> x.getKey()).collect(Collectors.toList());
32795 amit.gupta 1528
 
1529
                List<OfferPayout> partnerPayouts = offerPayouts.stream().filter(x -> x.getFofoId() == fofoId).collect(Collectors.toList());
32868 amit.gupta 1530
                Set<String> serialNumbersRejected = partnerPayouts.stream().filter(x -> x.getStatus().equals(SchemePayoutStatus.REJECTED)).map(x -> x.getSerialNumber()).collect(Collectors.toSet());
32795 amit.gupta 1531
 
34092 amit.gupta 1532
                Set<String> billedNotCancelledSerialNumbers;
32345 amit.gupta 1533
                LOGGER.info("warehouseInventoryItemIds {}", warehouseInventoryItemIds);
1534
                if (warehouseInventoryItemIds.size() > 0) {
1535
                    List<WarehouseInventoryItem> warehouseInventoryItems = warehouseInventoryItemRepository.selectAllByIds(warehouseInventoryItemIds);
34092 amit.gupta 1536
                    billedNotCancelledSerialNumbers = warehouseInventoryItems.stream().map(x -> x.getSerialNumber()).collect(Collectors.toSet());
31920 amit.gupta 1537
                } else {
34092 amit.gupta 1538
                    billedNotCancelledSerialNumbers = new HashSet<>();
31920 amit.gupta 1539
                }
34092 amit.gupta 1540
                LOGGER.info("billedNotCancelledSerialNumbers {}", billedNotCancelledSerialNumbers);
1541
 
31920 amit.gupta 1542
                Map<String, LineItem> serialNumberMap = lineItemImeisRepository.selectByLineItemIds(new ArrayList<>(lineItemMap.keySet()))
32868 amit.gupta 1543
                        .stream().filter(x -> !serialNumbersRejected.contains(x.getSerialNumber())).collect(Collectors.toMap(x -> x.getSerialNumber(), x -> lineItemMap.get(x.getLineItemId()), (x1, x2) -> x1.getId() > x2.getId() ? x1 : x2));
31920 amit.gupta 1544
 
34226 amit.gupta 1545
                List<String> manuallyEligibleImeis = offerEligibleImeiRepository.selectEligibleImeisByOfferId(createOfferRequest.getId());
32795 amit.gupta 1546
 
34092 amit.gupta 1547
                serialNumberMap = serialNumberMap.entrySet().stream().filter(x -> billedNotCancelledSerialNumbers.contains(x.getKey())).collect(Collectors.toMap(x -> x.getKey(), x -> x.getValue()));
34231 amit.gupta 1548
 
1549
                //Just a validation need to revaluate this
1550
                Map<String, InventoryItem> serialNumberInventoryItemMap = this.getInventoryItemMap(fofoId, serialNumberMap);
1551
                if (serialNumberInventoryItemMap.size() < billedNotCancelledSerialNumbers.size()) continue;
1552
 
34623 amit.gupta 1553
                LOGGER.info("serialNumberMap {}", serialNumberMap);
34226 amit.gupta 1554
                if (manuallyEligibleImeis != null) {
34227 amit.gupta 1555
                    serialNumberMap = serialNumberMap.entrySet().stream().filter(x -> manuallyEligibleImeis.contains(x.getKey())).collect(Collectors.toMap(x -> x.getKey(), x -> x.getValue()));
34624 amit.gupta 1556
                    if (serialNumberMap.size() == 0) continue;
34231 amit.gupta 1557
                    serialNumberInventoryItemMap = this.getInventoryItemMap(fofoId, serialNumberMap);
34226 amit.gupta 1558
                }
32543 amit.gupta 1559
                if (serialNumberMap.size() == 0) continue;
32064 amit.gupta 1560
                //Continue if all imeis havent been grned
1561
 
32345 amit.gupta 1562
 
33662 amit.gupta 1563
                float eligiblePayoutValue = eligibleSlab.getPayoutAmount();
32345 amit.gupta 1564
                double finalPayout;
1565
                if (AmountType.PERCENTAGE.equals(itemCriteriaPayout.getAmountType())) {
1566
                    finalPayout = (eligiblePayoutValue * purchasedValue) / 100;
1567
                } else if (AmountType.FIXED.equals(itemCriteriaPayout.getAmountType())) {
36051 amit 1568
                    // FIXED = per piece, use per-criteria qty not base value
1569
                    finalPayout = eligiblePayoutValue * totalQty;
32345 amit.gupta 1570
                } else {
33695 amit.gupta 1571
                    Map<Integer, Double> fofoCriteriaPayoutMap = fixedSlabCriteriaPartnerMap.get(criteriaId);
1572
                    LOGGER.info("fofoCriteriaMap {}", fofoCriteriaPayoutMap);
32345 amit.gupta 1573
                    finalPayout = eligiblePayoutValue;
33695 amit.gupta 1574
                    if (fofoCriteriaPayoutMap != null && fofoCriteriaPayoutMap.containsKey(fofoId)) {
1575
                        finalPayout = eligiblePayoutValue - fofoCriteriaPayoutMap.get(fofoId);
1576
                        if (Math.abs(finalPayout) < Utils.DOUBLE_EPSILON) {
1577
                            finalPayout = 0;
32345 amit.gupta 1578
                        }
31920 amit.gupta 1579
                    }
1580
                }
32345 amit.gupta 1581
 
1582
                LOGGER.info("Or - {}", finalPayout);
1583
 
1584
                if (finalPayout > 0) {
1585
                    double totalRolloutAmount = 0;
1586
                    int totalDpValue = serialNumberInventoryItemMap.entrySet().stream().mapToInt(x -> (int) x.getValue().getUnitPrice()).sum();
1587
                    for (Map.Entry<String, InventoryItem> serialNumberInventoryItemEntry : serialNumberInventoryItemMap.entrySet()) {
1588
                        double amount = 0;
1589
                        LOGGER.info("Total DP Value {}", totalDpValue);
1590
                        if (AmountType.SLAB_FIXED.equals(itemCriteriaPayout.getAmountType())) {
1591
                            amount = (eligiblePayoutValue * serialNumberInventoryItemEntry.getValue().getUnitPrice()) / totalDpValue;
1592
                            LOGGER.info("Amount - {}", amount);
1593
                        } else {
1594
                            amount = eligiblePayoutValue;
1595
                            if (serialNumberPaid.containsKey(serialNumberInventoryItemEntry.getKey())) {
34073 ranu 1596
                                LOGGER.info("serial number slab amount {}", serialNumberPaid.get(serialNumberInventoryItemEntry.getKey()));
32345 amit.gupta 1597
                                amount = amount - serialNumberPaid.get(serialNumberInventoryItemEntry.getKey());
1598
                            }
1599
                        }
1600
                        LOGGER.info("Amount - {}", amount);
1601
                        //ignore reasonably small
33662 amit.gupta 1602
                        if (Math.abs(amount) < Utils.DOUBLE_EPSILON) continue;
32345 amit.gupta 1603
                        AmountModel amountModel = new AmountModel();
1604
                        amountModel.setAmountType(itemCriteriaPayout.getAmountType());
1605
                        amountModel.setAmount(amount);
1606
                        amountModel.setDiscount(createOfferRequest.isDiscount());
1607
                        InventoryPayoutModel inventoryPayoutModel = priceCircularService.getPayouts(serialNumberInventoryItemEntry.getValue());
1608
                        double rolloutAmount = inventoryPayoutModel.getRolloutAmount(amountModel);
1609
                        totalRolloutAmount += rolloutAmount;
1610
 
1611
                        OfferPayout offerPayout = new OfferPayout(fofoId, createOfferRequest.getId(), criteriaId, amount, serialNumberInventoryItemEntry.getKey(), rolloutAmount, SchemePayoutStatus.CREDITED, createOfferRequest.getDescription(), LocalDateTime.now());
33459 amit.gupta 1612
                        offerPayout.setInventoryItemId(serialNumberInventoryItemEntry.getValue().getId());
32345 amit.gupta 1613
                        offerPayoutRepository.persist(offerPayout);
1614
                    }
34623 amit.gupta 1615
                    walletService.addAmountToWallet(fofoId, createOfferRequest.getId(), WalletReferenceType.ADDITIONAL_SCHEME, createOfferRequest.getDescription(), (float) totalRolloutAmount, LocalDateTime.now());
32345 amit.gupta 1616
                }
31920 amit.gupta 1617
            }
1618
        }
1619
        Offer offer = offerRepository.selectById(createOfferRequest.getId());
1620
        offer.setProcessedTimestamp(LocalDateTime.now());
1621
    }
32064 amit.gupta 1622
 
36305 amit 1623
    @Override
1624
    @Transactional(readOnly = true)
1625
    public List<SellinPartnerPayoutData> calculateSellinPayouts(CreateOfferRequest createOfferRequest) throws Exception {
1626
        List<SellinPartnerPayoutData> result = new ArrayList<>();
1627
 
1628
        List<OfferPayout> offerPayouts = offerPayoutRepository.selectAllByOfferId(createOfferRequest.getId());
1629
        Map<String, Double> serialNumberPaid = offerPayouts.stream()
1630
                .filter(x -> x.getRejectTimestamp() == null)
1631
                .collect(Collectors.groupingBy(x -> x.getSerialNumber(), Collectors.summingDouble(x -> x.getSlabAmount())));
1632
 
1633
        List<ItemCriteriaPayout> itemCriteriaPayouts = createOfferRequest.getTargetSlabs().get(0).getItemCriteriaPayouts();
1634
        Map<Integer, ItemCriteriaPayout> itemCriteriaPayoutMap = itemCriteriaPayouts.stream()
1635
                .collect(Collectors.toMap(x -> x.getItemCriteria().getId(), x -> x));
1636
        Map<Integer, Map<Integer, Double>> fixedSlabCriteriaPartnerMap = offerPayouts.stream()
1637
                .filter(x -> itemCriteriaPayoutMap.containsKey((int) x.getCriteriaId()) &&
1638
                        itemCriteriaPayoutMap.get((int) x.getCriteriaId()).getAmountType().equals(AmountType.SLAB_FIXED))
1639
                .collect(Collectors.groupingBy(x -> (int) x.getCriteriaId(),
1640
                        Collectors.groupingBy(x -> (int) x.getFofoId(), Collectors.summingDouble(x -> x.getSlabAmount()))));
1641
        Set<Long> fofoIds = offerPayouts.stream().map(x -> x.getFofoId()).collect(Collectors.toSet());
1642
 
1643
        Map<Integer, Map<Integer, List<Order>>> criteriaOrdersMap = offerRepository.getPartnerWiseSellin(createOfferRequest, true);
1644
 
1645
        Map<Integer, List<Order>> userBaseCriteriaOrdersMap = null;
1646
        if (criteriaOrdersMap.get(0) != null && criteriaOrdersMap.get(0).size() > 0) {
1647
            userBaseCriteriaOrdersMap = criteriaOrdersMap.get(0).entrySet().stream()
1648
                    .filter(x -> !fofoIds.contains(x.getKey())).collect(Collectors.toMap(x -> x.getKey(), x -> x.getValue()));
1649
        }
1650
 
1651
        Map<Integer, Integer> userBaseQtyMap = null;
1652
        Map<Integer, Integer> userBaseValueMap = null;
1653
        if (userBaseCriteriaOrdersMap != null) {
1654
            userBaseQtyMap = new HashMap<>();
1655
            userBaseValueMap = new HashMap<>();
1656
            for (Map.Entry<Integer, List<Order>> orderEntry : userBaseCriteriaOrdersMap.entrySet()) {
1657
                int fofoId = orderEntry.getKey();
1658
                List<Order> orders = orderEntry.getValue();
1659
                int totalBaseQty = orders.stream().collect(Collectors.summingInt(x -> (x.getLineItem().getQuantity() - x.getLineItem().getReturnQty())));
1660
                int totalBaseValue = orders.stream().collect(Collectors.summingInt(x ->
1661
                        Math.round(x.getLineItem().getUnitPrice() * (x.getLineItem().getQuantity() - x.getLineItem().getReturnQty()))
1662
                ));
1663
                userBaseQtyMap.put(fofoId, totalBaseQty);
1664
                userBaseValueMap.put(fofoId, totalBaseValue);
1665
            }
1666
        }
1667
 
1668
        for (ItemCriteriaPayout itemCriteriaPayout : createOfferRequest.getTargetSlabs().get(0).getItemCriteriaPayouts()) {
1669
            int criteriaId = itemCriteriaPayout.getItemCriteria().getId();
1670
            if (criteriaOrdersMap.get(criteriaId) == null) continue;
1671
            Map<Integer, List<Order>> ordersMap = criteriaOrdersMap.get(criteriaId).entrySet().stream()
1672
                    .filter(x -> !fofoIds.contains(x.getKey())).collect(Collectors.toMap(x -> x.getKey(), x -> x.getValue()));
1673
 
1674
            for (Map.Entry<Integer, List<Order>> orderEntry : ordersMap.entrySet()) {
1675
                int fofoId = orderEntry.getKey();
1676
                List<Order> orders = orderEntry.getValue();
1677
                int totalQty = orders.stream().collect(Collectors.summingInt(x -> (x.getLineItem().getQuantity() - x.getLineItem().getReturnQty())));
1678
                int totalValue = orders.stream().collect(Collectors.summingInt(x -> Math.round(x.getLineItem().
1679
                        getUnitPrice() * (x.getLineItem().getQuantity() - x.getLineItem().getReturnQty()))));
1680
                int totalBaseQty = totalQty;
1681
                int totalBaseValue = totalValue;
1682
                if (userBaseCriteriaOrdersMap != null) {
1683
                    if (userBaseQtyMap.containsKey(fofoId)) {
1684
                        totalBaseQty = userBaseQtyMap.get(fofoId);
1685
                        totalBaseValue = userBaseValueMap.get(fofoId);
1686
                    } else {
1687
                        continue;
1688
                    }
1689
                }
1690
 
1691
                int purchasedValue;
1692
                if (createOfferRequest.getTargetType().equals(AchievementType.VALUE)) {
1693
                    purchasedValue = totalBaseValue;
1694
                } else {
1695
                    purchasedValue = totalBaseQty;
1696
                }
1697
 
1698
                PayoutSlab eligibleSlab = null;
1699
                for (PayoutSlab payoutSlab : itemCriteriaPayout.getPayoutSlabs()) {
1700
                    if (payoutSlab.getOnwardsAmount() <= purchasedValue) {
1701
                        eligibleSlab = payoutSlab;
1702
                    } else {
1703
                        break;
1704
                    }
1705
                }
1706
                if (eligibleSlab == null) continue;
1707
 
1708
                List<Integer> orderIds = orders.stream().map(x -> x.getId()).collect(Collectors.toList());
1709
                Map<Integer, LineItem> lineItemMap = orders.stream().collect(Collectors.toMap(x -> x.getLineItem().getId(), x -> x.getLineItem()));
1710
                List<WarehouseScan> warehouseScans = warehouseScanRepository.selectAllByOrderIds(orderIds);
1711
                List<Integer> warehouseInventoryItemIds = warehouseScans.stream().collect(Collectors.groupingBy(x -> x.getInventoryItemId())).entrySet()
1712
                        .stream().filter(x -> x.getValue().size() == 1).map(x -> x.getKey()).collect(Collectors.toList());
1713
 
1714
                List<OfferPayout> partnerPayouts = offerPayouts.stream().filter(x -> x.getFofoId() == fofoId).collect(Collectors.toList());
1715
                Set<String> serialNumbersRejected = partnerPayouts.stream().filter(x -> x.getStatus().equals(SchemePayoutStatus.REJECTED)).map(x -> x.getSerialNumber()).collect(Collectors.toSet());
1716
 
1717
                Set<String> billedNotCancelledSerialNumbers;
1718
                if (warehouseInventoryItemIds.size() > 0) {
1719
                    List<WarehouseInventoryItem> warehouseInventoryItems = warehouseInventoryItemRepository.selectAllByIds(warehouseInventoryItemIds);
1720
                    billedNotCancelledSerialNumbers = warehouseInventoryItems.stream().map(x -> x.getSerialNumber()).collect(Collectors.toSet());
1721
                } else {
1722
                    billedNotCancelledSerialNumbers = new HashSet<>();
1723
                }
1724
 
1725
                Map<String, LineItem> serialNumberMap = lineItemImeisRepository.selectByLineItemIds(new ArrayList<>(lineItemMap.keySet()))
1726
                        .stream().filter(x -> !serialNumbersRejected.contains(x.getSerialNumber()))
1727
                        .collect(Collectors.toMap(x -> x.getSerialNumber(), x -> lineItemMap.get(x.getLineItemId()), (x1, x2) -> x1.getId() > x2.getId() ? x1 : x2));
1728
 
1729
                List<String> manuallyEligibleImeis = offerEligibleImeiRepository.selectEligibleImeisByOfferId(createOfferRequest.getId());
1730
 
1731
                serialNumberMap = serialNumberMap.entrySet().stream().filter(x -> billedNotCancelledSerialNumbers.contains(x.getKey()))
1732
                        .collect(Collectors.toMap(x -> x.getKey(), x -> x.getValue()));
1733
 
1734
                Map<String, InventoryItem> serialNumberInventoryItemMap = this.getInventoryItemMap(fofoId, serialNumberMap);
1735
                if (serialNumberInventoryItemMap.size() < billedNotCancelledSerialNumbers.size()) continue;
1736
 
1737
                if (manuallyEligibleImeis != null) {
1738
                    serialNumberMap = serialNumberMap.entrySet().stream().filter(x -> manuallyEligibleImeis.contains(x.getKey()))
1739
                            .collect(Collectors.toMap(x -> x.getKey(), x -> x.getValue()));
1740
                    if (serialNumberMap.size() == 0) continue;
1741
                    serialNumberInventoryItemMap = this.getInventoryItemMap(fofoId, serialNumberMap);
1742
                }
1743
                if (serialNumberMap.size() == 0) continue;
1744
 
1745
                float eligiblePayoutValue = eligibleSlab.getPayoutAmount();
1746
                double finalPayout;
1747
                if (AmountType.PERCENTAGE.equals(itemCriteriaPayout.getAmountType())) {
1748
                    finalPayout = (eligiblePayoutValue * purchasedValue) / 100;
1749
                } else if (AmountType.FIXED.equals(itemCriteriaPayout.getAmountType())) {
1750
                    finalPayout = eligiblePayoutValue * totalQty;
1751
                } else {
1752
                    Map<Integer, Double> fofoCriteriaPayoutMap = fixedSlabCriteriaPartnerMap.get(criteriaId);
1753
                    finalPayout = eligiblePayoutValue;
1754
                    if (fofoCriteriaPayoutMap != null && fofoCriteriaPayoutMap.containsKey(fofoId)) {
1755
                        finalPayout = eligiblePayoutValue - fofoCriteriaPayoutMap.get(fofoId);
1756
                        if (Math.abs(finalPayout) < Utils.DOUBLE_EPSILON) {
1757
                            finalPayout = 0;
1758
                        }
1759
                    }
1760
                }
1761
 
1762
                if (finalPayout > 0) {
1763
                    result.add(new SellinPartnerPayoutData(
1764
                            fofoId, criteriaId, finalPayout, eligiblePayoutValue,
1765
                            serialNumberInventoryItemMap, itemCriteriaPayout,
1766
                            serialNumberPaid, createOfferRequest.isDiscount()));
1767
                }
1768
            }
1769
        }
1770
 
1771
        return result;
1772
    }
1773
 
33441 amit.gupta 1774
    private void rollbackPayout(int fofoId, int offerId, List<
1775
            OfferPayout> partnerPayouts, Set<String> returnedSerialNumbers) throws ProfitMandiBusinessException {
32795 amit.gupta 1776
        LOGGER.info("Rollback payout called for offerId {}", offerId);
1777
        float amountToRollback = 0;
1778
        int totalImeis = 0;
1779
        for (OfferPayout partnerPayout : partnerPayouts) {
1780
            LOGGER.info("serialNumberInventoryItemMap - {}", returnedSerialNumbers);
1781
            LOGGER.info("Serial Number - {}", partnerPayout.getSerialNumber());
1782
            if (returnedSerialNumbers.contains(partnerPayout.getSerialNumber()) && partnerPayout.getStatus().equals(SchemePayoutStatus.CREDITED)) {
1783
                partnerPayout.setRejectTimestamp(LocalDateTime.now());
1784
                partnerPayout.setStatus(SchemePayoutStatus.REJECTED);
1785
                amountToRollback += partnerPayout.getAmount();
1786
                totalImeis += 1;
1787
            }
1788
        }
1789
        if (amountToRollback > 0) {
1790
            LOGGER.info("Amount to Rollback - {}", amountToRollback);
1791
            walletService.rollbackAmountFromWallet(fofoId, amountToRollback, offerId, WalletReferenceType.ADDITIONAL_SCHEME, "Stock Returned, total " + totalImeis + "pc(s)", LocalDateTime.now());
1792
        }
1793
    }
1794
 
33441 amit.gupta 1795
    private Map<String, InventoryItem> getInventoryItemMap(int fofoId, Map<String, LineItem> serialNumberMap) throws
1796
            ProfitMandiBusinessException {
36337 amit 1797
        if (serialNumberMap.isEmpty()) {
1798
            return new HashMap<>();
1799
        }
32064 amit.gupta 1800
        List<InventoryItem> inventoryItems = inventoryItemRepository.selectBySerialNumbers(serialNumberMap.keySet());
32345 amit.gupta 1801
        inventoryItems = inventoryItems.stream().filter(x -> x.getFofoId() == fofoId).collect(Collectors.toList());
1802
        Map<String, InventoryItem> inventoryItemMap = inventoryItems.stream().collect(Collectors.toMap(x -> x.getSerialNumber(), x -> x, (u, v) -> v.getCreateTimestamp().isAfter(u.getCreateTimestamp()) ? v : u));
32064 amit.gupta 1803
        return inventoryItemMap;
1804
    }
33030 amit.gupta 1805
 
1806
 
1807
    @Override
33247 ranu 1808
    public String getPartnerCriteriaString(PartnerCriteria partnerCriteria) throws ProfitMandiBusinessException {
33030 amit.gupta 1809
        StringBuilder sb = new StringBuilder();
1810
        if (partnerCriteria.getFofoIds().size() > 0) {
1811
            List<Integer> fofoIds = partnerCriteria.getFofoIds();
1812
            appendPartnerCodes(fofoIds, sb);
1813
 
1814
        } else {
1815
            sb.append("All");
1816
            if (partnerCriteria.getPartnerTypes().size() > 0) {
1817
                sb.append(" ").append(String.join(", ", partnerCriteria.getPartnerTypes().stream().map(x -> x.getValue()).collect(Collectors.toList())));
1818
            }
1819
            sb.append(" partners ");
1820
            if (partnerCriteria.getRegionIds().size() > 0) {
1821
                sb.append("from ");
37845 amit 1822
                sb.append(String.join(", ", partnerCriteria.getRegionIds().stream().map(x -> billingWarehouseService.getName(x)).collect(Collectors.toList())));
33030 amit.gupta 1823
            }
1824
            if (partnerCriteria.getExcludeFofoIds() != null && partnerCriteria.getExcludeFofoIds().size() > 0) {
35394 amit 1825
                sb.append("<b>excluding</b> ");
33030 amit.gupta 1826
                appendPartnerCodes(partnerCriteria.getExcludeFofoIds(), sb);
1827
            }
1828
        }
1829
        return sb.toString();
1830
    }
1831
 
33999 tejus.loha 1832
    @Override
1833
    public ByteArrayOutputStream createCSVOfferReport(CreateOfferRequest createOfferRequest) throws Exception {
1834
        List<List<?>> listOfRows = new ArrayList<>();
1835
        ByteArrayOutputStream baos = null;
1836
        Collection<OfferRowModel> offerRowModels = offerRepository.getOfferRows(createOfferRequest);
1837
        ItemCriteriaPayout itemCriteriaPayout = createOfferRequest.getTargetSlabs().get(0).getItemCriteriaPayouts().get(0);
35394 amit 1838
        // Batch fetch all retailers once to avoid N+1 queries
1839
        Map<Integer, CustomRetailer> allRetailers = retailerService.getAllFofoRetailers();
33999 tejus.loha 1840
        if (createOfferRequest.getSchemeType().equals(OfferSchemeType.SELLIN)) {
1841
            for (OfferRowModel offerRowModel : offerRowModels) {
35394 amit 1842
                CustomRetailer customRetailer = allRetailers.get(offerRowModel.getFofoId());
33999 tejus.loha 1843
                listOfRows.add(Arrays.asList(
1844
                        createOfferRequest.getId()
1845
                        , createOfferRequest.getName()
1846
                        , createOfferRequest.getTargetType()
1847
                        , createOfferRequest.getSchemeType()
1848
                        , itemCriteriaPayout.getStartDate()
1849
                        , itemCriteriaPayout.getEndDate()
1850
//                        , createOfferRequest.getBrandShareTerms()
1851
                        , createOfferRequest.getSellinPercentage()
1852
                        , "--"
1853
                        , createOfferRequest.getItemCriteriaString()
1854
                        , createOfferRequest.getStartDate()
1855
                        , createOfferRequest.getEndDate()
1856
                        , createOfferRequest.getCreatedOn()
1857
                        , customRetailer.getPartnerId()
1858
                        , customRetailer.getBusinessName()
1859
                        , customRetailer.getCode()
1860
                        , offerRowModel.getTotalBasePurchaseValue()
1861
                        , offerRowModel.getAchievedTarget()
1862
                        , offerRowModel.getPayoutPurchaseValue()
1863
                        , offerRowModel.getPayout()
1864
                        , offerRowModel.getPayoutType()
1865
                        , offerRowModel.getFinalPayout()
1866
                        , String.join(", ", offerRowModel.getEligibleImeis())));
1867
            }
1868
            baos = FileUtil.getCSVByteStream(
1869
                    Arrays.asList(
1870
                            "Id"
1871
                            , "Name"
1872
                            , "Target Type"
1873
                            , "Scheme Type"
1874
                            , "Payout Start"
1875
                            , "Payout End"
1876
//                            , "Brand %"
1877
                            , "Sellin %"
1878
                            , "Partner Criteria"
1879
                            , "Item Criteria"
1880
                            , "Start"
1881
                            , "End"
1882
                            , "Created"
1883
                            , "Partner Id"
1884
                            , "Partner Name"
1885
                            , "Partner Code"
1886
                            , "Base Purchase"
1887
                            , "Achieved Target"
1888
                            , "Eligible Purchase"
1889
                            , "Slab Amount"
1890
                            , "Slab Amount Type"
1891
                            , "Payout Value(Rs.)"
1892
                            , "Eligible IMEIs"
1893
                            , "Billing Pending Imeis"
1894
                    ), listOfRows);
1895
        } else {
1896
            for (OfferRowModel offerRowModel : offerRowModels) {
35394 amit 1897
                CustomRetailer customRetailer = allRetailers.get(offerRowModel.getFofoId());
33999 tejus.loha 1898
                listOfRows.add(Arrays.asList(
1899
                                createOfferRequest.getId()
1900
                                , createOfferRequest.getName()
1901
                                , createOfferRequest.getTargetType()
1902
                                , createOfferRequest.getSchemeType()
1903
                                , itemCriteriaPayout.getStartDate()
1904
                                , itemCriteriaPayout.getEndDate()
1905
//                                , createOfferRequest.getBrandShareTerms()
1906
                                , createOfferRequest.getSellinPercentage()
1907
                                , createOfferRequest.getPartnerCriteriaString()
1908
                                , createOfferRequest.getItemCriteriaString()
1909
                                , createOfferRequest.getStartDate()
1910
                                , createOfferRequest.getEndDate()
1911
                                , createOfferRequest.getCreatedOn()
1912
                                , customRetailer.getPartnerId()
1913
                                , customRetailer.getBusinessName()
1914
                                , customRetailer.getCode()
1915
                                , offerRowModel.getTotalSale()
1916
                                , offerRowModel.getEligibleSale()
1917
                                , offerRowModel.getPayoutTargetAchieved()
1918
                                , offerRowModel.getPayoutValue()
1919
                                , offerRowModel.getPayoutType()
1920
                                , offerRowModel.getPayoutValueDp()
1921
                                , offerRowModel.getFinalPayout()
1922
                                , String.join(", ", offerRowModel.getEligibleImeis())
1923
//                        ,String.join(", ", offerRowModel.getBaseCriteria())
1924
                        )
1925
                );
1926
            }
1927
            baos = FileUtil.getCSVByteStream(
1928
                    Arrays.asList(
1929
                            "Id"
1930
                            , "Name"
1931
                            , "Target Type"
1932
                            , "Scheme Type"
1933
                            , "Payout Start"
1934
                            , "Payout End"
1935
//                            , "Brand %"
1936
                            , "Sellin %"
1937
                            , "Partner Criteria"
1938
                            , "Item Criteria"
1939
                            , "Start"
1940
                            , "End"
1941
                            , "Created"
1942
                            , "Partner Id"
1943
                            , "Partner Name"
1944
                            , "Partner Code"
1945
                            , "Total Sale"
1946
                            , "Eligible Sale"
1947
                            , "Payout Target Achieved"
1948
                            , "Payout Amount"
1949
                            , "Payout Amount Type"
1950
                            , "Payout Value DP"
1951
                            , "Amount to be credited"
1952
                            , "Eligible Activated Imeis"
1953
                    ), listOfRows);
1954
        }
1955
        return baos;
1956
    }
1957
 
35205 amit 1958
    @Override
1959
    public void sendWhatsapp(Offer offer, List<Integer> fofoIds, String imageUrl) throws Exception {
1960
        if (fofoIds == null) {
1961
            fofoIds = fofoStoreRepository.selectActiveStores().stream().map(x -> x.getId()).collect(Collectors.toList());
1962
        }
1963
        final List<Integer> finalFofoIds = fofoIds;
1964
        //List<String> mobileNumbers = retailerService.getAllFofoRetailers().entrySet().stream().filter(x -> finalFofoIds.contains(x.getKey())).map(x -> x.getValue().getMobileNumber()).collect(Collectors.toList());
1965
        List<String> mobileNumbers = new ArrayList<>();
1966
        mobileNumbers.add("9911565032");
1967
        //mobileNumbers.add("9990381569");
1968
        //mobileNumbers.add("8383849914");
1969
        //TV's mobile
37409 vikas 1970
        // The wording lives in the approved Meta template; only these four values vary per offer.
35205 amit 1971
        for (String mobileNumber : mobileNumbers) {
37409 vikas 1972
            notificationService.sendOfferAnnouncement(mobileNumber, offer.getName(),
35205 amit 1973
                    offer.getSchemeType().toString(), FormattingUtils.formatDate(offer.getStartDate()),
37409 vikas 1974
                    FormattingUtils.formatDate(offer.getEndDate()), imageUrl);
35205 amit 1975
        }
1976
    }
1977
 
33247 ranu 1978
    private void appendPartnerCodes(List<Integer> fofoIds, StringBuilder sb) throws ProfitMandiBusinessException {
33030 amit.gupta 1979
        Map<Integer, CustomRetailer> customRetailersMap = retailerService.getAllFofoRetailers();
33031 amit.gupta 1980
        List<String> businessNames = fofoIds.stream().map(x -> customRetailersMap.get(x)).filter(x -> x != null).map(x -> x.getBusinessName()).collect(Collectors.toList());
33030 amit.gupta 1981
        sb.append(String.join(", ", businessNames));
1982
    }
35856 amit 1983
 
1984
    @Override
1985
    public void deleteOffer(int offerId) throws ProfitMandiBusinessException {
1986
        Offer offer = offerRepository.selectById(offerId);
1987
        if (offer == null) {
1988
            throw new ProfitMandiBusinessException("Offer not found", "Offer not found", "");
1989
        }
1990
        if (offer.isActive()) {
1991
            throw new ProfitMandiBusinessException("Cannot delete a published offer", "Cannot delete a published offer", "");
1992
        }
36521 amit 1993
        this.evictOfferCaches(offerId);
35856 amit 1994
        List<TargetSlabEntity> targetSlabs = offerTargetSlabRepository.selectByOfferIds(Collections.singletonList(offerId));
1995
        for (TargetSlabEntity targetSlab : targetSlabs) {
1996
            genericRepository.delete(targetSlab);
1997
        }
1998
        genericRepository.delete(offer);
1999
        LOGGER.info("Deleted offer {} and {} target slabs", offerId, targetSlabs.size());
2000
    }
2001
 
2002
    @Override
36633 amit 2003
    @Transactional(propagation = Propagation.REQUIRES_NEW)
35856 amit 2004
    public List<Offer> publishAllUnpublished(YearMonth yearMonth) throws ProfitMandiBusinessException {
2005
        List<Offer> allOffers = offerRepository.selectAll(yearMonth, false);
2006
        List<Offer> unpublished = allOffers.stream().filter(o -> !o.isActive()).collect(Collectors.toList());
2007
        for (Offer offer : unpublished) {
2008
            offer.setActive(true);
2009
        }
2010
        LOGGER.info("Published {} unpublished offers for {}", unpublished.size(), yearMonth);
2011
        return unpublished;
2012
    }
35885 amit 2013
 
2014
    @Override
2015
    public void removePartnersFromOffer(int offerId, List<Integer> fofoIds) throws ProfitMandiBusinessException {
2016
        Offer offer = offerRepository.selectById(offerId);
2017
        if (offer == null) {
2018
            throw new ProfitMandiBusinessException("Offer not found", "Offer not found", "");
2019
        }
2020
        PartnerCriteria partnerCriteria = gson.fromJson(offer.getPartnerCriteria(), PartnerCriteria.class);
2021
        if (partnerCriteria.getFofoIds() != null) {
2022
            partnerCriteria.getFofoIds().removeAll(fofoIds);
2023
        }
2024
        offer.setPartnerCriteria(gson.toJson(partnerCriteria));
2025
        genericRepository.persist(offer);
2026
        LOGGER.info("Removed partners {} from offer {}", fofoIds, offerId);
2027
    }
2028
 
2029
    @Override
2030
    public void addPartnersToOffer(int offerId, List<Integer> fofoIds) throws ProfitMandiBusinessException {
2031
        Offer offer = offerRepository.selectById(offerId);
2032
        if (offer == null) {
2033
            throw new ProfitMandiBusinessException("Offer not found", "Offer not found", "");
2034
        }
2035
        PartnerCriteria partnerCriteria = gson.fromJson(offer.getPartnerCriteria(), PartnerCriteria.class);
2036
        List<Integer> existingFofoIds = partnerCriteria.getFofoIds();
2037
        if (existingFofoIds == null) {
2038
            existingFofoIds = new ArrayList<>();
2039
        }
2040
        for (int fofoId : fofoIds) {
2041
            if (!existingFofoIds.contains(fofoId)) {
2042
                existingFofoIds.add(fofoId);
2043
            }
2044
        }
2045
        partnerCriteria.setFofoIds(existingFofoIds);
2046
        offer.setPartnerCriteria(gson.toJson(partnerCriteria));
2047
        genericRepository.persist(offer);
2048
        LOGGER.info("Added partners {} to offer {}", fofoIds, offerId);
2049
    }
2050
 
2051
    @Override
2052
    public int cloneOfferForPartners(int sourceOfferId, List<Integer> fofoIds, List<Integer> targets) throws ProfitMandiBusinessException {
2053
        Offer sourceOffer = offerRepository.selectById(sourceOfferId);
2054
        if (sourceOffer == null) {
2055
            throw new ProfitMandiBusinessException("Source offer not found", "Source offer not found", "");
2056
        }
2057
        CreateOfferRequest clonedRequest = this.getCreateOfferRequest(sourceOffer);
2058
        clonedRequest.setId(0);
2059
        clonedRequest.setActive(false);
2060
 
2061
        PartnerCriteria newPartnerCriteria = new PartnerCriteria();
2062
        newPartnerCriteria.setFofoIds(new ArrayList<>(fofoIds));
2063
        newPartnerCriteria.setExcludeFofoIds(new ArrayList<>());
2064
        newPartnerCriteria.setRegionIds(clonedRequest.getPartnerCriteria().getRegionIds() != null
2065
                ? new ArrayList<>(clonedRequest.getPartnerCriteria().getRegionIds()) : new ArrayList<>());
2066
        newPartnerCriteria.setPartnerTypes(clonedRequest.getPartnerCriteria().getPartnerTypes() != null
2067
                ? new ArrayList<>(clonedRequest.getPartnerCriteria().getPartnerTypes()) : new ArrayList<>());
2068
        clonedRequest.setPartnerCriteria(newPartnerCriteria);
2069
 
2070
        if (targets != null && !targets.isEmpty() && !clonedRequest.getTargetSlabs().isEmpty()) {
2071
            List<PayoutSlab> payoutSlabs = clonedRequest.getTargetSlabs().get(0).getItemCriteriaPayouts()
2072
                    .stream().flatMap(x -> x.getPayoutSlabs().stream()).collect(Collectors.toList());
2073
            int counter = 0;
2074
            for (PayoutSlab payoutSlab : payoutSlabs) {
2075
                if (counter < targets.size()) {
2076
                    payoutSlab.setOnwardsAmount(targets.get(counter));
2077
                    counter++;
2078
                }
2079
            }
2080
        }
2081
 
2082
        this.addOfferService(clonedRequest);
2083
        LOGGER.info("Cloned offer {} to new offer {} for partners {}", sourceOfferId, clonedRequest.getId(), fofoIds);
2084
        return clonedRequest.getId();
2085
    }
2086
 
2087
    @Override
2088
    public void updateOfferTargets(int offerId, List<Integer> newTargets) throws ProfitMandiBusinessException {
2089
        Offer offer = offerRepository.selectById(offerId);
2090
        if (offer == null) {
2091
            throw new ProfitMandiBusinessException("Offer not found", "Offer not found", "");
2092
        }
2093
        List<TargetSlabEntity> targetSlabs = offerTargetSlabRepository.selectEntitiesByOfferId(offerId);
2094
        targetSlabs.sort(Comparator.comparing(TargetSlabEntity::getPayoutTarget));
2095
 
35889 amit 2096
        // Group slabs by unique payout_target (multiple item_criteria share the same target value)
2097
        LinkedHashMap<Integer, List<TargetSlabEntity>> groupedByTarget = new LinkedHashMap<>();
2098
        for (TargetSlabEntity slab : targetSlabs) {
2099
            groupedByTarget.computeIfAbsent(slab.getPayoutTarget(), k -> new ArrayList<>()).add(slab);
2100
        }
2101
        List<Integer> uniqueTargets = new ArrayList<>(groupedByTarget.keySet());
2102
 
2103
        if (newTargets.size() != uniqueTargets.size()) {
35885 amit 2104
            throw new ProfitMandiBusinessException(
35889 amit 2105
                    "Target count mismatch. Expected " + uniqueTargets.size() + " but got " + newTargets.size(),
35885 amit 2106
                    "Target count mismatch", "");
2107
        }
35889 amit 2108
 
2109
        // Update each group: all slabs sharing the same old target get the new target value
2110
        for (int i = 0; i < uniqueTargets.size(); i++) {
2111
            int oldTarget = uniqueTargets.get(i);
2112
            int newTarget = newTargets.get(i);
2113
            if (oldTarget != newTarget) {
2114
                for (TargetSlabEntity slab : groupedByTarget.get(oldTarget)) {
2115
                    genericRepository.updateById(TargetSlabEntity.class, "payoutTarget", newTarget, slab.getId());
2116
                }
2117
            }
35885 amit 2118
        }
2119
        LOGGER.info("Updated targets for offer {} to {}", offerId, newTargets);
2120
    }
35924 amit 2121
 
2122
    @Override
2123
    public void updateOfferSlabs(com.spice.profitmandi.dao.model.UpdateOfferSlabsRequest request) throws ProfitMandiBusinessException {
2124
        Offer offer = offerRepository.selectById(request.getOfferId());
2125
        if (offer == null) {
2126
            throw new ProfitMandiBusinessException("Offer not found", "Offer not found", "");
2127
        }
2128
 
2129
        List<TargetSlabEntity> existingSlabs = offerTargetSlabRepository.selectEntitiesByOfferId(request.getOfferId());
2130
        Set<Integer> validSlabIds = existingSlabs.stream().map(TargetSlabEntity::getId).collect(Collectors.toSet());
2131
 
2132
        for (com.spice.profitmandi.dao.model.UpdateSlabRequest slab : request.getSlabs()) {
2133
            if (!validSlabIds.contains(slab.getId())) {
2134
                throw new ProfitMandiBusinessException("Invalid slab ID " + slab.getId(),
2135
                        "Slab does not belong to offer " + request.getOfferId(), "");
2136
            }
2137
            genericRepository.updateById(TargetSlabEntity.class, "payoutTarget", slab.getPayoutTarget(), slab.getId());
2138
            genericRepository.updateById(TargetSlabEntity.class, "payoutValue", slab.getPayoutValue(), slab.getId());
2139
        }
2140
        LOGGER.info("Updated slabs for offer {}: {}", request.getOfferId(), request.getSlabs());
2141
    }
27877 amit.gupta 2142
}