Subversion Repositories SmartDukaan

Rev

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